© Brady Somerville, Adam Gamble, Cloves Carneiro Jr and Rida Al Barazi 2020
B. Somerville et al.Beginning Rails 6https://doi.org/10.1007/978-1-4842-5716-6_7

7. Action Pack: Working with Routes, Controllers, and Views

Brady Somerville1 , Adam Gamble2, Cloves Carneiro Jr.3 and Rida Al Barazi4
(1)
Bowling Green, KY, USA
(2)
Gardendale, AL, USA
(3)
Hollywood, FL, USA
(4)
FONTHILL, ON, Canada
 

When you type a URL into your browser’s address bar and press Enter, a few things happen behind the scenes. First, the domain name is translated into a unique address by which the server that hosts the application can be identified. The request is then sent to that server, which begins a chain of events that culminates in a response. The response is usually, but not always, in the form of an HTML document, which is essentially a text document full of special code that your browser understands and can render visually on your screen. At this point, the request cycle is complete, and the browser waits for further input from you. If you click a link somewhere on the page or type a new URL in the address bar, the cycle begins all over again: the request is sent, the server processes it, and the server sends back the response.

When you make a request to a Rails application, this request cycle is the responsibility of a component of Rails called Action Pack. The Action Pack library is an integral component of the Rails framework and one that you need to be familiar with if you intend to master Rails.

This chapter begins with an overview of Action Pack. Then, you get to work using it in your sample blog application.

Note

If you need to get the code at the exact point where you finished Chapter 6, download the source code zip file from the book’s page on www.apress.com and extract it on your computer.

Action Pack Components

You’ve been introduced to the MVC pattern, but if you need a refresher, here it is. The model is your application’s world, most often represented by database objects like articles, comments, and subscribers. The controller is the grand orchestrator, dealing with requests and issuing responses. The view is the code that contains instructions for rendering visual output for a browser, like HTML.

Armed with this refresher, you may be able to guess what roles are played by Action Pack. This isn’t a test, so here’s the answer: Action Pack is the controller and the view. The controller performs the logic, and the view renders the template that is given back to the requesting browser. Not surprisingly, two of the modules that make up the Action Pack are named accordingly: Action Controller and Action View.

Action Pack has another important component: Action Dispatch. A typical Rails app has multiple controllers—each of which handles requests for a particular area of concern. (For example, in previous chapters, we built ArticlesController, which returns responses for requests specific to articles.) How does Rails know which controller should handle a particular request? Action Dispatch, among other things, handles routing—which decides which controller should handle a given request.

At this point, you may be wondering why the router, view, and controller are wrapped up in a single library, unlike models, which have a library of their own. The answer is subtle and succinct: routes, controllers, and views are very closely related. The sections that follow paint a more complete picture of both the role and the relationship of controllers and views, how they work, and how they work together to create and control the interface of a Rails application.

Action Controller

Controllers orchestrate your application’s flow. Every time a user requests a page, submits a form, or clicks a link, that request is handled—in one way or another—by a controller. When you’re programming your application, you spend a lot of time building controllers and giving them instructions on how to handle requests.

The concept of controllers can sometimes be difficult for newcomers to grasp. Even if you’ve built web applications before, say in ASP (Active Server Pages) or PHP (PHP Hypertext Preprocessor), you may not be used to this form of separation, where the mechanics of flow are controlled by a separate entity and not embedded in the pages themselves.

Let’s look at the example of the CD player in a car to illustrate the concept of controllers. The player is required to respond to certain events, such as the user pressing the play button, fast-forwarding, or rewinding a track. When you push a button, you expect something to happen—you’ve made a request, and you wait for the subsequent response.

If your CD player were a Rails application, the instructions for what to do when a certain event takes place, such as pressing the eject button, would be contained in a controller. If you were to sketch it on paper, it might look something like this:
  • CD Player

  • Play

  • Stop

  • Fast-forward

  • Rewind

  • Eject

These events, or actions, describe what the player should be capable of doing. Obviously, each of these actions would need to be programmed to do something with the disk inside the player. When someone presses Eject, you would first call on the stop action (if the disk is playing) and then arrange for the player to spit out the disk. You would code all the instructions for dealing with an eject event into the controller—specifically, inside the eject action. The same would apply for play, fast-forward, and rewind.

It’s worth noting that this type of logic has nothing to do with the CD itself, nor does it have anything to do with the music on the CD. If this were a Rails application, the CD would be the model. It can be used independently of the player. In fact, it can be used in all sorts of players, not just the one in your car.

The stereo in your car is probably capable of more than just playing CDs. Most stereos have a radio receiver built in as well. The radio would have its own set of events that would likewise need to be handled. These actions might include things like changing stations, setting presets, and switching between AM and FM. To keep things well organized, you would probably want to group these actions inside their own controller, separate from the CD controller. After all, the radio and the CD player do different things.

When you’re dealing with a Rails application, it’s not much different. You separate the things that you need your application to do with an object from the object itself. Even when you’re not dealing directly with an object (adjusting the volume on your car stereo has little to do with either the CD in the player or the station on the radio), you still handle the event inside a controller.

Each controller in Rails is designed as a Ruby class. Without getting too technical, Listing 7-1 shows how the CD player example would look if it were a Ruby class.
class CDPlayer
  def play
  end
  def stop
  end
  def fast_forward
  end
  def rewind
  end
  def eject
  end
end
Listing 7-1

CDPlayer Class

Inside the CDPlayer class, you define a method for each action, or each thing you want your CD player to be able to do. So, if you were to send the message “play” to an instance of the CDPlayer class, it would know how to handle it (of course, because the play method is empty in this example, nothing would happen). On the other hand, if you sent the message “pause,” Ruby would raise an exception and tell you that the method wasn’t found. If you wanted CDPlayer objects to respond to that message, you would need to add a method called (you guessed it) pause.

All the methods in this class are public, which means they can be invoked by anyone. You don’t need to do anything special to a method to make it public. Unless otherwise declared, all methods in a Ruby class are public by default. If you were to mark an action as private, though, it could be used only internally by the class. For example, if the stop method were private, it would raise a NoMethodError if you called it from outside the CDPlayer class. However, the eject method is free to call on stop, because it does so internally. Although the usefulness of this feature will become apparent as you continue to learn about controllers, consider this: if your CD player needed to display the time remaining for a given track, it might need to perform a few calculations to figure that out. You might create a method for doing these internal calculations, but would you want that method to be accessible from the outside? Would you have a button called Calculate on your player?

It’s time for a working definition: Action Controllers are Ruby classes containing one or more public methods known as actions. Each action is responsible for responding to a request to perform some task. A typical controller is most often a collection of actions that relates to a specific area of concern. For example, consider the blog application you’ve been building in the previous chapters. The controller that manages articles has the class name ArticlesController and has action methods for listing, creating, reading, updating, and deleting articles.

The example of the CD player worked well to illustrate the basic concept of controllers, but it won’t take you much further when dealing with web applications. If you were really dealing with a CD player, you would press Play, the disc would start playing, and that would be the end of it. But because Rails was specifically designed for building web applications, it makes a fair number of assumptions about what you want your actions to do when they’re finished firing. Chief among these is the rendering of a view.

Imagine that you’re reading a list of posts on someone’s blog. You click the title of a post, and you expect to be taken to a new screen that shows you just that post. You requested an action (show), and in response, you receive a new screen. This happens all the time in the world of web applications: when you click a link, you expect to go to a new page.

In Rails, it’s the general case that when actions have completed their work, they respond by rendering a view. The concept of actions rendering views is so common that Rails has internalized it as a convention: unless otherwise stated, when an action is finished firing, it renders a view. How does Rails know what view to render if you don’t tell it? It looks for a view whose name matches that of the requested action. This should give you some insight as to why Action Controller and Action View are bundled together in Action Pack. Because of the way controller actions relate to views, a few other mechanisms facilitate their communication, all of which are covered shortly.

Action View

The Action View library is another important part of Action Pack. Given that controllers are responsible for handling the request and issuing a response, views are responsible for rendering the output of a response in a way a browser (or any other user agent) can understand. Let’s say you request the index action from the ArticlesController. After performing the logic to retrieve a list of articles, the controller hands off to the view, which formats the list of articles to make them look pretty. The controller then collects the results of the render, and the HTML is sent back to the browser, thus completing the request cycle.

Although the controller and the view are separate entities, they need to communicate with each other. The primary mechanism by which they do this is through shared variables. These shared variables are called instance variables and are easy to spot in Ruby because they’re prefixed with the @ symbol. Keep this in mind as you look at the view example in Listing 7-2, which uses an instance variable called @articles to produce an articles listing.
<html>
  <body>
    <ul>
      <% @articles.each do |article| %>
        <li><%= article.title %></li>
      <% end %>
    <ul>
  </body>
</html>
Listing 7-2

An Example View

Even without knowing any Ruby, you should be able to guess what this code does: it iterates over the collection of articles stored in the variable @articles and prints the title of each between HTML list item (<li>) tags. If @articles contained three articles whose titles were One, Two, and Three, respectively, the preceding code would be compiled to the following:
<html>
  <body>
    <ul>
      <li>One</li>
      <li>Two</li>
      <li>Three</li>
    <ul>
  </body>
</html>

You may wonder where the variable @articles came into being. If you guessed in the controller, you would be right. The controller sets up instance variables that the view can access. In this case, the controller created a variable called @articles, and the view was given automatic access to it. Notice that the view doesn’t perform any logic to fetch the list of articles; it relies on the controller to have set up the variable and performs the display logic necessary to turn the collection into a browser-ready HTML list.

Embedded Ruby

The code you see mixed into the HTML markup is Ruby. Because templates that are capable of dealing only with static HTML wouldn’t be very useful, Action View templates have the benefit of being able to use Embedded Ruby (ERb) to programmatically enhance them.

Using ERb, you can embed Ruby into your templates and give them the ability to deal with data from the controller to produce well-formed HTML representations. ERb is included in the Ruby Standard library, and Rails makes extensive use of it. You trigger ERb by using embeddings such as <% %> and <%= %> in your template files to evaluate or print Ruby code, respectively. If you’ve ever worked with ASP, JSP (Java Server Page), or PHP, this style of embedding should be familiar to you.

In the example in the preceding section, the loop is constructed within evaluation embedding tags (<% %>), and the article’s title is printed using output embedding tags (<%= %>). Pay close attention to the subtle difference between the two embedding types: output embedding includes an equals sign; regular embedding doesn’t. When you use output embedding, you’re effectively saying print the results of the Ruby code when it’s evaluated. Regular embedding doesn’t print results; it evaluates whatever is between the tags and goes on its merry way. If you mistakenly omit the equals sign, no errors are raised, but nothing is printed either. You have a set of empty list tags.

Note

Following the Model behavior, Rails is modular and can be used with other templating libraries. A popular alternative is the Haml (http://haml-lang.com) template language used by many Rails developers.

Helpers

The terms of the MVC are fairly strict in the way they advocate the separation of components. Controllers really shouldn’t concern themselves with the generation of view code, and views shouldn’t concern themselves with anything but the simplest of logic. Although it’s possible to use ERb to execute arbitrary Ruby code inside a view, and although controllers are certainly capable of generating markup, it’s generally considered in violation of the MVC pattern to do so. This is where helpers come in to play.

Action Pack’s helpers do exactly what their name implies: they help views by providing a convenient location to encapsulate code that would otherwise clutter the view and violate the terms of the MVC. They offer a middle ground between controllers and views and help to keep your application organized and easy to maintain.

If you think about it, ERb tags really aren’t the best place for performing complex logic, and templates can quickly become unwieldy when creating markup programmatically. For this reason, Action Pack includes a large suite of built-in helpers for generating all sorts of HTML fragments—from creating forms and formatting dates to making hyperlinks and image tags. And when the built-in helpers aren’t enough, you can write your own. Each controller gets its own helper module that’s mixed in automatically, ready to lend your templates a hand when they need it.

Routing

All the information pertaining to which controller and action to call on comes in the form of the request URL. Action Pack includes a specialized component called routing, which is responsible for dissecting the incoming URL and delegating control to the appropriate controller and action.

Every request that comes into your web application originates in the form of a URL. The routing system allows you to write the rules that govern how each URL is picked apart and handled.

A traditional URL contains the path to a file on the server, relative to the server’s home directory. Here’s an example:
http://example.com/articles/show.asp?id=1037

You can tell a lot from this URL. First, you know the server technology being used is Microsoft’s ASP. Given that, you also know that this URL resolves to the show.asp script, which is inside the /articles directory. In this case, there is no URL rewriting going on; the mapping of the URL to the script that handles it is one-to-one.

The problem with this kind of mapping is that you have no control over the URL. The URL is coupled to the script. What if you want to invoke the show.asp script but want the URL to read articles/detail.asp instead of show.asp? Or better yet, what if you don’t want to expose the underlying script implementation (ASP) at all and use just articles/detail? There’s no way. The lack of flexibility in this kind of URL mapping is a problem. If you ever need to change the name of the script being invoked, you instantly break all the URL references. This can be a major pain if you need to update all your code, especially if your pages are indexed by search engines.

Action Pack’s routing solves this problem by decoupling the URL from the underlying program implementation. In Rails, the URL is related to the specific resource being requested, and it can be formatted to correctly identify that resource without having to conform to the name of the script that does the handling. When thought of in this way, URLs become part of the interface of an application, unrelated to the files that are ultimately invoked to process a request.

There are myriad reasons why a routing system is a good idea. Here are just a few of them:
  • Decoupled URLs can convey meaning, becoming part of the interface.

  • Clean, readable URLs are more user-friendly and easier to remember.

  • URLs can be changed without affecting the underlying implementation.

Of course, like most things in Rails, the routing system is open to configuration; and one of the great benefits of routes is that because they’re decoupled, they can be customized to create meaningful URLs without much effort. This chapter teaches you how to build and customize routes for your application, understand the default routes that Rails creates for you, create named routes, and use routes when creating links and redirects in your code.

RESTful Resources

Rails adapted RESTful design as a convention in Rails 1.2 onward. Representational State Transfer (REST) is a principle used mainly over the HTTP protocol to offer a better interface for client-server operations. This section first discusses the REST concept and then explains how Rails implemented it through RESTful controllers and resources.

The REST principle is based on working with information in the form of resources. Each piece of information is dealt with as a resource, each resource has a unique interaction point for every action that can be performed on it, and each interaction point (action) is normally represented using a URL and a request method.

For example, think of a blog, which is a collection of information resources. Every article is a resource, and every action you perform on it, such as read, edit, or delete, has its own interaction point, mainly identified by a URL and a request method.

HTTP protocol, which is the main web protocol you normally use in browsers, has several request methods. These are the primary ones used in RESTful design:
  • POST: Normally used to submit forms and create new resource data

  • GET: Mainly used to request a page to view a resource or more

  • PATCH/PUT: Used to modify a specific resource

  • DELETE: Used to delete a resource

Do those methods remind you of anything? If you’re thinking of CRUD, then you’re right. Taking the main database operations create, read, update, and delete (CRUD) in REST design and tying them up with HTTP’s main methods gives you what’s called a RESTful web service.

RESTful web services are commonly used in APIs (referred to as REST APIs) by associating every CRUD method with its corresponding HTTP method:
  • POST/Create: Creates a resource

  • GET/Read: Requests a specific resource or group of resources

  • PATCH/PUT/Update: Edits attributes of a resource

  • DELETE/Delete: Deletes a resource

Rails implemented RESTful design for controllers by introducing the concept of resources. Every model in your application is dealt with via a controller as a resources set, and that RESTful controller has certain methods that handle your regular operations on that model. We’ll examine that in depth after you understand the Action Pack request cycle.

Action Pack Request Cycle

The entire request-to-response process is called the Action Pack request cycle . The request cycle consists of the following steps:
  1. 1.

    Rails receives a request from the outside world (usually a browser).

     
  2. 2.

    Routing picks apart the request to determine the controller and action to invoke.

     
  3. 3.

    A new controller object is instantiated, and an action method is called.

     
  4. 4.

    The controller interacts with a model (usually performing a CRUD operation in a database with an ActiveRecord model, but not necessarily).

     
  5. 5.

    A response is sent back to the browser, in the form of either a render or a redirect.

     
Figure 7-1 illustrates the process.
../images/314622_4_En_7_Chapter/314622_4_En_7_Fig1_HTML.jpg
Figure 7-1

The Action Pack request cycle

Not long ago (and still today), developers used to construct server pages. Such a page had a bunch of code at the top of an otherwise static page, just above the opening HTML tag. The markup was littered with different sorts of code: it wasn’t unusual to see the database being accessed, forms being processed, sessions being set, and all manner of logic being performed in line. The web server was responsible for controlling the application—one page redirecting to another, running the code, and then dumping the results to the screen. For example, consider this poorly written PHP code:
<?php
  // articles.php
  require_once("db.inc.php");
  require_once("header.inc.php");
  $result = mysql_query("SELECT * FROM articles") or die(mysql_error());
?>
<table>
    <tr>
     <th>Title</th>
     <th>Excerpt</th>
      <?php
        if($logged_in) {
          echo "<th>Actions</th>";
        }
      ?>
    </tr>
    <?php
      while($a = mysql_fetch_array($result)) {
        echo "<tr>";
        echo "<td><a href='/article.php?id=".$a['id']."'>" . $a['title'] . "</a></td>";
        echo "<td>" . $a['excerpt'] . "</td>";
        if ($logged_in) {
          echo "<td>";
            echo "<td><a href='/edit.php?id=".$a['id']."'>Edit</a></td>";
            echo "<td><a href='/delete.php?id=".$a['id']."'>Delete</a></td>";
          echo "</td>";
        }
        echo "</tr>";
      }
    ?>
</table>
<?php
    require_once("footer.inc.php");
?>

This isn’t even that bad of an example! We won’t get into the multitude of reasons why this is a bad idea, except to say that it presents the problem of coupling. In this scenario, the business logic and the view are mashed together, making the code more difficult to maintain and debug. ASP and PHP pages are notable offenders, and if you’re coming from either of these camps, the concept of separating concerns may be foreign at first. Here’s a way to think about it that may help. Imagine taking the code and logic from the top of each page and sticking it in one place, leaving only the HTML behind. Then, instead of using the web server to invoke each page as you would with a static site, have the web server call on a single dispatcher, which finds the code you want to execute and calls it. The code it invokes—the file that contains the processing logic extracted from the server page—is called the controller. Instead of logic being divided among pages, it’s divided into actions.

The single biggest advantage of this pattern is that the processing logic is decoupled from the view and safely contained in one place. As you can see, it’s a lot easier to work this way. The interplay between actions is considerably easier to visualize and understand when it isn’t spread out over a host of locations. Your server pages become lightweight views, left to handle only the simplest of instructions, if any.

A Controller Walk-Through

Instead of boring you with more theory about controllers, views, and MVC, let’s dig in and start writing some real-world code. You’ll continue building your blog application, examining the finer points and the places where convention wins out over configuration. Along the way, this section touches on some of the most essential controller and view concepts. By the end of this walk-through, you should have a complete grasp of how the Rails request cycle works and a working example to refer to and expand on in the subsequent chapters. The purpose of this walk-through isn’t to examine each and every aspect of Action Pack in detail, but rather to give you a practical overview of how the components—routes, controllers, helpers, views, layouts, and partials—work together to control your application and construct its interface.

Setting Up Routes

Links and URLs are important in web applications. They serve as the entry point to the application and contain all the information required to route an incoming request to the controller and action that will handle it. Before you get into the meat of understanding controllers and their actions, you need to spend a few minutes learning how to get from request to response. It all starts with routing.

Routing Basics

In Rails, all the rules for mapping URLs to controllers are a matter of configuration. You find the routes.rb file in the config directory.

Routing priority is based on the order in which routes exist in routes.rb, so that the first route defined has the highest priority. If an incoming URL matches the first route defined, the request is sent along, and no other routes are examined.

Here’s an example that matches a specific pattern and sets the controller and action in response:
get '/teams/home', to: 'teams#index'
This route matches a URL like http://example.com/teams/home and routes the request to the index action on the teams controller. The names of the controller and action are separated by the # symbol. You can also set arbitrary parameters when using the route. For example, let’s say you want to set a parameter called query that you can access and use in your controller:
get '/teams/search/:query', to: 'teams#search'

This route matches a URL like http://example.com/teams/search/toronto, routing the request to the teams controller and the search action. The third segment in the URL is assigned to the :query parameter and passed to the search action, because you specify :query as an inline variable.

Routes can be complex, and it’s possible to apply conditions and other forms of logic to them. For the most part, though, you can get a lot of mileage from the general cases outlined here. The Rails API documentation (https://guides.rubyonrails.org/routing.html) contains details on using the more complex routing features.

Named Routes

One of the coolest things about routing in Rails is a feature known as named routes. You can assign a name to a given route to make referring to it in code easier. You still define the route the same way as a regular route, but you need a new hash pair, where the key is :as and the value is the name of the route.

For example, let’s take the search route defined in the previous section and turn it into a named route:
get '/teams/search/:query', to: 'teams#search', as: 'search'

With this definition in place, Rails creates helper methods that allow you to reference this particular route using its name: search_url and search_path. The *_url variant returns a full URL including the protocol and hostname (http://example.com/teams/search), whereas the *_path variant returns just the path (/teams/search).

Later in this chapter, we’ll cover redirection methods and hyperlink generation helpers. For now, note that you can use them with named routes:
link_to "Search", search_path
outputs
<a href="/teams/search">Search</a>

Named routes are shorter, DRYer, and impervious to changes made at the routing level. So if you change the controller name from teams to cities, you don’t need to update links that use the named route; for the unnamed version, you do.

RESTful Routes and Resources

Earlier, we said that RESTful design information is dealt with in the form of resources. Rails makes it easy for you to do that: for every action in your controller, you have an associated named route to call.

Resources are configured in the routes.rb file using the resources method. If you look at the routes file in your blog application, you see resources :articles at the top: it was added when you generated the articles scaffold in Chapter 3. The resources :articles method defines the following named routes for the articles controller:
article_path => /articles/:id
articles_path => /articles
edit_article_path => /articles/:id/edit
new_article_path => /articles/new
The resources method generated four named routes for you; but when you open the ArticlesController, you have seven actions (Table 7-1). How can you access the remaining actions? Remember that when you learned about REST earlier, you saw that every operation is identified by both a URL and a request method. Using different request methods with the generated named routes, Rails routes them to the appropriate controller actions.
Table 7-1

Articles Named Routes

Request Method

Named Routes

Parameters

Controller Action

GET

articles_path

 

index

POST

articles_path

Article attributes

create

GET

new_article_path

 

new

GET

edit_article_path

ID

edit

GET

article_path

ID

show

PATCH

article_path

ID and article attributes

update

PUT

article_path

ID and article attributes

update

DELETE

article_path

ID

destroy

Note

You can list all the available routes in your application by running the rails routes command from the terminal. You can also view a list of routes by going to http://localhost:3000/rails/info in your browser while you have your Rails server running in development mode.

By following the REST convention, instead of defining a named route for every action, you use the resources method in your routes file. To give some examples, if you want to access the index action in your articles controller, you go to /articles in your browser; the default request method when you type a URL in your browser is GET. What if you want to create a new article? You can do that by submitting a form to /articles with the default request method for forms, POST. To get a specific article, type /articles/:id, where :id is your article id. It’s that simple.

Configuring Routes for the Blog Application

Let’s configure the routes to be used in your blog application. You haven’t built all the controllers and actions yet (you do that next), but that shouldn’t stop you from getting the routes in place.

You can handle an empty request for the root of your application’s domain using the root method. In the blog application, you want the root URL (http://localhost:3000) to connect to the list of articles. To accomplish this, you add a root declaration to your routes file and make it the first route. Make sure your config/routes.rb file looks like Listing 7-3 (note that all comments have been deleted).
Rails.application.routes.draw do
  root to: "articles#index"
  resources :articles
end

Now, visit the root URL of your project (http://localhost:3000). You should see the articles listing, just like on http://localhost:3000/articles. Now that we have some routes defined, let’s move back to the articles controller and try to understand its actions and templates.

Revisiting the Scaffold Generator

You generated a scaffold for your articles in Chapter 3, and this scaffold generated a RESTful controller for the Article model in addition to all the required templates. The generator also added the resources declaration to your route.rb file. Listing 7-4 shows the ArticlesController that your scaffold generated.
class ArticlesController < ApplicationController
  before_action :set_article, only: [:show, :edit, :update, :destroy]
  # GET /articles
  # GET /articles.json
  def index
    @articles = Article.all
  end
  # GET /articles/1
  # GET /articles/1.json
  def show
  end
  # GET /articles/new
  def new
    @article = Article.new
  end
  # GET /articles/1/edit
  def edit
  end
  # POST /articles
  # POST /articles.json
  def create
    @article = Article.new(article_params)
    respond_to do |format|
      if @article.save
        format.html { redirect_to @article, notice: 'Article was successfully created.' }
        format.json { render :show, status: :created, location: @article }
      else
        format.html { render :new }
        format.json { render json: @article.errors, status: :unprocessable_entity }
      end
    end
  end
  # PATCH/PUT /articles/1
  # PATCH/PUT /articles/1.json
  def update
    respond_to do |format|
      if @article.update(article_params)
        format.html { redirect_to @article, notice: 'Article was successfully updated.' }
        format.json { render :show, status: :ok, location: @article }
      else
        format.html { render :edit }
        format.json { render json: @article.errors, status: :unprocessable_entity }
      end
    end
  end
  # DELETE /articles/1
  # DELETE /articles/1.json
  def destroy
    @article.destroy
    respond_to do |format|
      format.html { redirect_to articles_url, notice: 'Article was successfully destroyed.' }
      format.json { head :no_content }
    end
  end
  private
    # Use callbacks to share common setup or constraints between actions.
    def set_article
      @article = Article.find(params[:id])
    end
    # Never trust parameters from the scary internet, only allow the white list through.
    def article_params
      params.require(:article).permit(:title, :location, :excerpt, :body, :published_at)
    end
end
Listing 7-4

The ArticlesController app/controllers/articles_controller.rb

This may look like a lot of code to swallow, but in reality it’s simple. The scaffold generator creates the articles controller with the default seven actions discussed earlier for RESTful controllers: index, show, new, edit, create, update, and destroy.

Before your action renders a view, you arrange for it to set an instance variable that the view can use. To refresh your memory, an instance variable is a special kind of Ruby variable that is unique to a given instance of a class, serving as a way for an object to maintain its state. Because views are, in essence, extensions of the controller object, they can access its instance variables directly (although not without some behind-the-scenes Ruby magic that Rails takes care of for you). For all intents and purposes, however, you can consider instance variables to be shared between controllers and views.

You can store any Ruby object in an instance variable, including strings, integers, models, hashes, and arrays. If you reexamine each action in the articles controller, notice that it always starts by setting an instance variable to be called later in that action’s view. Let’s take the index method as an example (Listing 7-5).
  # GET /articles
  # GET /articles.json
  def index
    @articles = Article.all
  end
Listing 7-5

The Index Action in app/controllers/articles_controller.rb

You define and set an instance variable named @articles, which holds the array of all your articles.

Let’s step back a bit. When you call the index method by typing the URL (http://localhost:3000/articles) into your browser—don’t forget to start your local server using the rails server command—the request goes first to your routes file, where it’s forwarded to the controller. Then, the controller responds to this request by setting an instance variable and rendering something back to the browser.

What the controller renders is based on what has been requested. Normally, it’s an HTML page request, but it can also be an XML or an Ajax request. It’s the responsibility of the respond_to method to define how to respond to each of those requests. In the index action, you accept two formats: HTML, where Rails renders the index template using the path (/articles), and JSON (JavaScript Object Notation), where Rails renders the articles in JSON format using the path (/articles.json). In this case, the respond_to method is implicit, which means that since we didn’t need to change any options, it will just use the defaults. You will see the respond_to method actually used when we look at later actions.

Try that in the browser. Visit http://localhost:3000/articles to see the list of articles you know and saw earlier, and visit http://localhost:3000/articles.json to see the result shown in Figure 7-2.
../images/314622_4_En_7_Chapter/314622_4_En_7_Fig2_HTML.jpg
Figure 7-2

Output of http://localhost:3000/articles.json

Get An API For Free

Using RESTful controllers in Rails gives you the ability to have an API for your application. An API is a set of functions that enables other applications to talk to your application. On the Web, this is normally done using JSON, and REST is one of the main architectures used for that.

With Rails and its RESTful controllers, defining your API is a seamless process; basically, you just need to tell your controller to respond to JSON requests, and you have an API. What’s neat in Rails is that the scaffold generator adds the JSON part by default to all your controller actions, providing you with an API for free. Rails also supports XML, but JSON is the default.

Rendering Responses

When an action has completed, it attempts to render a template of the same name. That’s the case with the index action just discussed: it renders the index.html.erb template by default. The same applies to edit, new, and show actions. But sometimes you want to render something else.

If you look at the create and update actions, notice that if the @article.save succeeds, you redirect to the saved @article show page with a friendly message. However, if the save fails, you want to render the new or the edit template. If you didn’t explicitly render those templates, the actions would fall through to their default behavior and attempt to render their default create and update templates, which don’t exist.

Typically, the first argument to render is a string or symbol indicating which template to render (e.g., render :edit when the update action in our ArticlesController fails to save would cause the articles/edit.html.erb to be rendered). However, the render method offers various ways to render output inline—that is, without a template. For example, render json: @article.errors results in the article’s errors being sent back to the browser in JSON format, with no template file involved. In addition to json, the render method supports several other inline-render modes, including :plain, :html, :nothing, :inline, :xml, and :js. For more information on different ways to use the render method, visit the following link when you’re ready: https://guides.rubyonrails.org/layouts_and_rendering.html#using-render

Redirecting

It may not sound like it, but a redirection is a response. Redirects don’t happen on the server side. Instead, a response is sent to your browser that tells it to perform a redirection to another URL. The specifics of issuing a redirect aren’t something you need to worry about, though, because Rails provides a specialized method to take care of the internals. That method is called redirect_to, and it’s one you’ll find yourself using a lot, so it’s a good idea to get familiar with it.

The redirect_to method usually takes a URL as a parameter, which in most cases is represented by one of your routes. Let’s say that you want to redirect the user to the articles’ index page, and the path you use is articles_path—a route added by resources :articles in config/routes.rb; so you execute redirect_to(articles_path). If you look at the destroy action, the user is redirected to articles_url after an article is deleted.

As you can see from the create and update actions, redirect_to can also take an object as a parameter, in which case it redirects to a path that represents that object. This means Rails uses a convention to translate objects to their show action named route. In this case, redirect_to(@article) is a shortcut equivalent to redirect_to(article_path(id: @article)).

What Makes a Class An Action Controller?
If you’re the curious sort (and, of course, you are), you may wonder how ArticlesController, a seemingly normal Ruby class, becomes a full-fledged Action Controller. Well, if you look closely, you’ll notice that ArticlesController inherits from another class: ApplicationController. To get a better picture of what’s going on, let’s take a peek at the ApplicationController class in app/controllers/application_controller.rb:
class ApplicationController < ActionController::Base
end

The mystery is quickly solved. The simple controller becomes an Action Controller by subclassing the ApplicationController class, itself a subclass of ActionController::Base. This is an example of inheritance and is common in object-oriented programming. When one class subclasses another, it inherits all the behavior and methods of the parent. In the case of the articles controller, it inherits all the capabilities of the ApplicationController. Likewise, ApplicationController inherits all the capabilities of its parent, ActionController::Base. The ActionController::Base class effectively endows your articles controller with its special abilities.

ApplicationController is the base from which all the controllers you make inherit. Because it’s the parent of all controllers in your application, it’s a great place to put methods that you want accessible in every controller.

By looking at the articles controller, you now understand the basic conventions and common concepts of how a RESTful controller normally behaves. You have seven default actions, and in every one of them you do the following:
  • Set an instance variable to be used later in the rendered action or template.

  • Handle the response using the respond_to method to either do a render or redirect_to another path, depending on the behavior you want to achieve.

Understanding Templates

The next step is to look at the actions’ templates. Look in the app/views/articles directory, and you see eight templates:
  • _article.json.jbuilder

  • _form.html.erb

  • edit.html.erb

  • index.html.erb

  • index.json.jbuilder

  • new.html.erb

  • show.html.erb

  • show.json.jbuilder

The basic convention of Action Pack is as follows: templates are organized by controller name, and a template with the same name as the action being invoked is rendered automatically. You don’t need to wire up anything. Merely by requesting an action from a controller, Rails renders the corresponding template in that controller’s directory inside app/views/ that has the same name.

Let’s try an example. Make sure your local web server is running (rails server), and open http://localhost:3000/articles/ in your browser. You see the articles index page shown in Figure 7-3.
../images/314622_4_En_7_Chapter/314622_4_En_7_Fig3_HTML.jpg
Figure 7-3

Output of http://localhost:3000/articles

The articles listing is actually rendered from app/views/articles/index.html.erb, which follows the convention discussed earlier. It’s the articles controller, so it goes to the articles directory in app/views. After determining which controller to invoke, Rails proceeds to instantiate it and calls its index method. Its default response after running the index action is to perform a render. Rails looks for a template named index.html.erb in the app/views/articles directory and loads it. The same applies to the show action: the show.html.erb template is rendered.

At this point, the request cycle is complete. If you refresh your browser, the cycle begins anew, and the same result is rendered. Notice how all the internals are taken care of for you. All you need to do is create an appropriately named route, controller, action, and view, stick them in the right place, and request the URL in your browser. Rails takes care of making sure everything is knit together properly.

Before you go any further, use your browser’s View Source command to see the HTML that was produced. If you know anything about HTML (and chances are you do), you’ll quickly realize that some additional HTML code has been rendered around the code in index.html.erb; it came from a layout. Most web pages have headers, footers, sidebars, and other page elements that, when styled, make the page look pretty. Rails has a built-in facility for dealing with page layouts.

Working with Layouts

Rails uses layouts to interpolate the output of an individual template into a larger whole—a reversal of the common pattern of including a shared header and footer on every page (which, if you’ve done any work in languages like PHP and ASP, is all too familiar). When you created this blog application, Rails created a default layout file and placed it in app/views/layouts/application.html.erb. The application.html.erb layout is applied to all controllers. However, if you like your layout to apply to a specific controller, you can create a layout file named after the controller you want. For example, a layout that applies only to the articles controller should be created in app/views/layouts/articles.html.erb. That’s the way it works in Rails. Just as an action tries to render itself using a view that matches its name, a controller attempts to use a layout that matches its name.

Note

Layouts always default to the most specific declaration. If your controller inherits from ApplicationController and doesn’t specify a layout directly, Rails will look for a layout named after your controller first. If that layout isn’t found, it will look for a layout declaration on ApplicationController, and if that isn’t found, it will look for a layout named application. In other words, layout declaration follows normal class inheritance.

Open the file app/views/layouts/application.html.erb in your editor. You should see something like the file shown in Listing 7-6.
<!DOCTYPE html>
<html>
  <head>
    <title>Blog</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>
    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>
  <body>
    <%= yield %>
  </body>
</html>
Listing 7-6

The app/views/layouts/application.html.erb File

At rendering time, the layout yields the results of the template fragment’s execution in place. See the <%= yield %> bit that’s highlighted in bold? That’s the important part. Wherever you put the yield keyword is where your content goes.

One more thing to note: Rails is all about convention over configuration. Here, the convention is that a layout with the name application.html.erb is automatically applied to all templates unless an alternate is specified. This means that if you change the name of the layout as it stands, it won’t be automatically applied. If you want to apply a different layout to a given controller, you can either have a layout named after the controller or specify it in the controller using the class method layout:
class ExampleController < ApplicationController
  layout 'my_layout' # Will use a layout in app/views/layouts/my_layout.html.erb
end
Common Layout Conventions
A few conventions apply to working with layouts:
  • A layout named application.html.erb is applied automatically unless a more specific candidate exists or is explicitly specified in the controller.

  • A layout that matches the name of a controller is automatically applied if present. Controller-specific layouts take precedence over the application-level layout.

  • You can use the layout directive at the class level in any controller (i.e., not inside an action) to set the layout for the entire controller: layout 'my_layout'.

  • You can include a layout for a specific action with an explicit call to render inside the action: render layout: 'my_layout'.

  • Sometimes, you want to render an action without a layout. In that case, you can pass false in place of the layout name: render layout: false.

In practice, you usually use application.html.erb and rarely take advantage of the controller-specific layout functionality. On the occasions when you need to use a different layout for a particular controller, use the layout directive.

Looking at the Article Form

Let’s look at the new template in action. The new action has a single purpose: to initialize and display the form for creating a new article. The actual creation of a new Article object is the responsibility of the Article model (remember the discussions of the model in Chapters 5 and 6), but it’s orchestrated by the controller. Moreover, it needs data (like a title and body), which it must procure from somewhere. The edit action isn’t any different, except that it finds and displays a form of an existing Article object rather than a new one.

You can extract this information from HTML form elements placed in the view and handled in the controller. Open new.html.erb and edit.html.erb, which look like Listings 7-7 and 7-8, respectively.
<h1>New Article</h1>
<%= render 'form', article: @article %>
<%= link_to 'Back', articles_path %>
Listing 7-7

Content of app/views/articles/new.html.erb

<h1>Editing Article</h1>
<%= render 'form', article: @article %>
<%= link_to 'Show', @article %> |
<%= link_to 'Back', articles_path %>
Listing 7-8

Content of app/views/articles/edit.html.erb

Notice the similarity between the templates, especially the render 'form' part highlighted in bold. The render method renders a partial named form in this context. The upcoming section “Staying DRY with Partials” discusses partials in more depth; for now, let’s focus on the content of the template in app/views/articles/_form.html.erb (Listing 7-9).
<%= form_with(model: article, local: true) do |form| %>
  <% if article.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(article.errors.count, "error") %> prohibited this article from being saved:</h2>
      <ul>
        <% article.errors.full_messages.each do |message| %>
          <li><%= message %></li>
        <% end %>
      </ul>
    </div>
  <% end %>
  <div class="field">
    <%= form.label :title %>
    <%= form.text_field :title %>
  </div>
  <div class="field">
    <%= form.label :location %>
    <%= form.text_field :location %>
  </div>
  <div class="field">
    <%= form.label :excerpt %>
    <%= form.text_field :excerpt %>
  </div>
  <div class="field">
    <%= form.label :body %>
    <%= form.text_area :body %>
  </div>
  <div class="field">
    <%= form.label :published_at %>
    <%= form.datetime_select :published_at %>
  </div>
  <div class="actions">
    <%= form.submit %>
  </div>
<% end %>
Listing 7-9

Content of app/views/articles/_form.html.erb

Notice how instead of including the actual markup for form fields (like <input> or <select> tags), you use form helpers for each of your fields. Visit the article’s new page at http://localhost:3000/articles/new in your browser, and you’ll see that the helpers function to produce a nicely formatted HTML form. Use your browser’s View Source command to look at the HTML that was generated. Here’s part of the generated HTML:
 <h1>New Article</h1>
<form action="/articles" accept-charset="UTF-8" method="post"><input type="hidden" name="authenticity_token" value="Yc+I0EOM4OdEefg/+BFZErrmAcRVWbZfNuTwG6a4MAFbIvJJlc9Xni51jjXYLlqYqYLrD+/K/vNvWZV+CfGxXA==" />
  <div class="field">
    <label for="article_title">Title</label>
    <input type="text" name="article[title]" id="article_title" />
  </div>
  <div class="field">
    <label for="article_location">Location</label>
    <input type="text" name="article[location]" id="article_location" />
  </div>
  <div class="field">
    <label for="article_excerpt">Excerpt</label>
    <input type="text" name="article[excerpt]" id="article_excerpt" />
  </div>
  <div class="field">
    <label for="article_body">Body</label>
    <textarea name="article[body]" id="article_body"></textarea>
  </div>
  ...
    <div class="actions">
    <input type="submit" name="commit" value="Create Article" data-disable-with="Create Article" />
  </div>
</form>

Note the way in which Rails formats the name attribute of each form element: model[attribute]. This helps when it comes to parsing the parameters from the form, as you’ll see shortly. If you manually create your form elements (which you need to do sometimes), you can use this naming convention to make sure your form values are easy to parse in the controller. Most of the time, though, you use form helpers when working with forms, especially when you’re dealing with Active Record objects. Let’s spend some time discussing form helpers.

Using Form Helpers

One of the best things about working with templates in Rails is the presence of helpers. Rails comes with a bunch of helper methods that take the tedium out of generating the bits of HTML that your views need. Let’s face it, nothing is more of a drag to build than HTML forms. Fortunately, Rails understands the plight of the web developer all too well and provides a suite of easy ways to build forms.

Two basic varieties of form helpers are available:
  • FormHelper: Active Record–aware tag helpers for creating forms that hook into models.

  • FormTagHelper: Helpers that output tags. They aren’t integrated with Active Record. The names of these helpers are suffixed with _tag.

The FormHelper type is aware of Active Record objects assigned to the template; the FormTagHelper (note the Tag) type isn’t. The advantage of the Active Record–aware, FormHelper, helpers is that they know how to populate themselves with data and can automatically be highlighted in the event of validation errors from the model. But not every form element you make corresponds directly to a model attribute. That’s where the FormTagHelper group comes in handy. These have no special relationship with Active Record; they just output form tags.

In your article’s form template (Listing 7-9), you use six helpers: form_with, label, text_field, text_area, datetime_select, and submit.

The form_with helper is of the FormHelper variety. It creates an HTML form tag using its parameters (model: article, local: true, in this case) and places everything in the do..end block inside the resulting form. It also produces and sets a form local variable to the form block. The form local variable, in this case called f, is aware of the Article object and uses its attributes’ names and values when calling the other form helpers: label, text_field, text_area, datetime_select, and submit.

By default, forms use the HTTP POST method. If you want to use a different method, you need to specify it manually using the :method option (e.g., method: "get"). If you recall, POST is the request method you used for the create action in your RESTful-designed controller.

HTTP verbs

The HTTP protocol defines several request methods, the most popular of which are GET and POST. Both are methods for requesting a web page; the difference is in how the request is sent. GET is the simpler of the two. It includes all the information about the request as part of the URL. POST sends information invisibly, which is to say as part of the request header and not part of the URL. So you can’t type a POST request into your browser’s location bar. Every time you request a web page via the location bar in your browser, you’re using GET. When you submit a form, say, to register on a website, the form is usually submitted via a POST.

How do you know when to use each? The best way to think of this is to consider GET a read method. It should never do anything destructive, such as modifying a database record. POST, on the other hand, can be thought of as a write method. When you need to create data, use POST. PATCH is used when you need to update a record partially, for instance, only changing your email address. PUT is used to update a record completely. There has been a lot of controversy over these verbs on the Internet, but they are effectively used interchangeably in Rails. The DELETE verb is used to destroy a record.

A small note: Most browsers only support the GET and POST verbs. Rails gets around this by using an actual POST request but inserting hidden form fields specifying which actual verb to use. Rails automatically removes this field and converts the request into the specified type. Once the request has reached the controller, it will appear as the intended verb.

Remember that you should never put a state-changing action behind a GET request. For more information, see www.w3.org/2001/tag/doc/whenToUseGet.html.

The label helper is a FormHelper method that outputs an HTML label tag for the provided attribute. Here’s an example of the output for :title:
<label for="article_title">Title</label>
The text_field helper is of the FormHelper variety, meaning that it corresponds to Active Record objects. It creates an HTML input tag whose type is set to "text" and assigns it a name and an ID that match the given object and method (title in this case). Here’s what the rendered output looks like:
<input type="text" name="article[title]" id="article_title" />
The text_area helper is also of the FormHelper variety. It’s similar to text_field, except it returns a text area instead of a text input. Here’s what the HTML output looks like for the body field:
<textarea name="article[body]" id="article_body"></textarea>

The datetime_select helper is a FormHelper that outputs a set of HTML select tags to input a date and time value.

The submit helper is a FormHelper that creates an input element whose type is set to "submit". It accepts the name of the submit button as its first argument. If you don’t provide a name to the submit method, it generates a name based on the @article object. For example, in the New Article form, the generated name is Create Article, whereas in the Edit Article form, the name is Update Article. Here’s the HTML output from the example:
<input type="submit" name="commit" value="Create Article" data-disable-with="Create Article" />
All these helpers (and, to be sure, most helpers in Rails) accept a hash of options as their last argument to customize the resulting HTML. For example, to give your title field a class of large, you type f.text_field :title, class: 'large', which adds the class attribute to the output:
<input class="large" type="text" name="article[title]" id="article_title" />
You can pass arbitrary options in this way, all of which end up as attributes on the resulting tag. For example, to apply an inline style attribute, you can use style: 'background: #fab444'. Here’s a list of some of the most common FormHelper helpers:
  • text_field

  • hidden_field

  • password_field

  • file_field

  • text_area

  • check_box

  • radio_button

All these methods can be suffixed with _tag to create standard HTML tags (with no Active Record integration).

For a full list of FormHelper and FormTagHelper methods, consult the Rails API, where you can find a complete reference along with usage examples:
Now, back to your form. Let’s see what happens when you submit it. (Make sure your server is still running.) Click the Create Article button, and you see the screen shown in Figure 7-4.
../images/314622_4_En_7_Chapter/314622_4_En_7_Fig4_HTML.jpg
Figure 7-4

New article form with validation errors

What happened? Well, as the message says, Rails couldn’t create an article for you. Of course it couldn’t—you set validation rules in your Article model to prevent the creation of a new Article object with an empty title or body field. But let’s look at the output from the server running in the command prompt and see what happened:
Started POST "/articles" for ::1 at 2020-02-22 14:40:13 -0600
Processing by ArticlesController#create as HTML
  Parameters: {"authenticity_token"=>"UzFLTMzE6SOnFXLUbbpUlSwAxJ2tJeAVkFRmSunZXEbKH4f/IQ0VhxyGnUBNkcCrDrqJClaFpzLi4o7U3nb3Yg==", "article"=>{"title"=>"", "location"=>"", "excerpt"=>"", "body"=>"", "published_at(1i)"=>"2020", "published_at(2i)"=>"2", "published_at(3i)"=>"22", "published_at(4i)"=>"20", "published_at(5i)"=>"40"}, "commit"=>"Create Article"}
  Rendering articles/new.html.erb within layouts/application
  Rendered articles/_form.html.erb (Duration: 5.2ms | Allocations: 3887)
  Rendered articles/new.html.erb within layouts/application (Duration: 5.6ms | Allocations: 3979)
[Webpacker] Everything's up-to-date. Nothing to do
Completed 200 OK in 28ms (Views: 12.4ms | ActiveRecord: 0.0ms | Allocations: 10155)
See the section titled Parameters in the preceding code? You may recognize this as a Ruby hash. This hash contains all the form values you submitted. Notice that there’s an entry for the button name (commit), called Create Article, and for authenticity_token, which is used for security in Rails to prevent anonymous form posts. The article portion of the hash looks like this:
"article"=>{"title"=>"", "location"=>"", "excerpt"=>"", "body"=>"", "published_at(1i)"=>"2020", "published_at(2i)"=>"2", "published_at(3i)"=>"22", "published_at(4i)"=>"20", "published_at(5i)"=>"40"}

If you’re thinking that this looks a lot like the options hashes you passed to Article objects when you were working with Active Record on the console, you’re right. Rails automatically turns form elements into a convenient hash that you can pass into your models to create and update their attributes. In the sections that follow, you’ll put this feature to use in the next action, create. First, let’s take a deeper look at params.

Processing Request Parameters

Request parameters—whether they originate from requests of the GET or POST variety—are accessible via the params hash. To be specific, params is a method that returns a Hash-like ActionController::Parameters object so you can access it using hash semantics. Hashes in Ruby are similar to arrays but are indexed by arbitrary keys—unlike arrays, which are indexed by number. (If you need a quick review of the Hash object, flip to Chapter 4 for a Ruby primer.)

The value of any request variable can be retrieved by its symbolized key. So, if there’s a variable called id in the request parameters, you can access it with params[:id]. Just to drive this concept home, let’s look at a sample URL and display the params hash that it populates. Point your browser to http://localhost:3000/articles?title=rails&body=great and check the server output. You should see something similar to this:
Parameters: {"title"=>"rails", "body"=>"great"}

Revisiting the Controller

With an understanding of params under your belt, let’s go back to your controller. The create action is the target of the form submission. The method code shown in Listing 7-10 is from the articles controller, just under the new method.
# POST /articles
# POST /articles.json
def create
  @article = Article.new(article_params)
  respond_to do |format|
    if @article.save
      format.html { redirect_to @article, notice: 'Article was successfully created.' }
      format.json { render :show, status: :created, location: @article }
    else
      format.html { render :new }
      format.json { render json: @article.errors, status: :unprocessable_entity }
    end
  end
end
Listing 7-10

The Create Action in app/controllers/articles_controller.rb

Let’s walk through this. First, you initialize a new Article object with whatever attributes come in via the article_params method. You can imagine that taking raw input from the user and putting it directly into your model without filtering it could be dangerous. Imagine that you were letting users sign up using the User#create action. If you had an attribute on the User model called admin that determined whether or not the user had admin access to the system, a user could just add that parameter in themselves and make themselves an admin. You can see how vital it is that we filter the parameters now! Let’s take a look at the article_params method:
# Never trust parameters from the scary internet, only allow the white list through.
def article_params
  params.require(:article).permit(:title, :location, :excerpt, :body, :published_at)
end

The syntax for this is simple. We are telling Rails that we require the article param and permit title, location, excerpt, body, and published at. Any other params will be filtered out before they get to the model. If you try to just pass params[:article] to the new or create method, an error will be returned. This feature is called “strong parameters.”

After we pass the filtered params to the new method, we attempt to save the model. If the save is successful, you use a facility that Rails provides called the flash to set a message—by passing the :notice option to redirect_to—before redirecting to the show action on the same articles controller. The flash is a special kind of storage mechanism provided by Rails for convenience. It encapsulates the pattern of wanting to set a message on one action and have that message persist to the next, only to disappear after that action is rendered. This is useful for providing user feedback, as you do here to say “Article was successfully created.” If you look at the show article file in app/views/articles/show.html.erb, you have access to the notice variable, allowing the message to be displayed:
<p class="notice"><%= notice %></p>

The flash message you set is available to the controller and action you redirect to (the show action on the articles controller). There are two special flash cases, notice and alert, which you can use just as you did in the previous example by passing them as arguments to redirect_to.

Note

When you pass notice: "Article was successfully created" to redirect_to, it’s identical to calling flash[:notice] = "Article was successfully created" in a separate line. Also, when you retrieve, in any view template, the message using notice, you could as well use flash[:notice]. So you can use any named key when calling flash because it’s implemented as a Ruby hash. You store values in it based on a key. The key can be anything you like: you can use any symbol, such as flash[:warning] =, in your controller and later retrieve it in your views using the same flash[:warning] call.

If the save fails, you render the new action again so that any errors can be corrected.

Displaying Error Messages in Templates

Let’s try submitting the form empty one more time to explore it again. Sure enough, the form doesn’t save. Notice that you’re still on the same screen and that the form elements are highlighted in red, as shown in Figure 7-4.

If you look at the HTML source, you see that the input and label tags are surrounded by div elements with the class name field_with_errors:
<div class="field_with_errors">
    <label for="article_title">Title</label>
</div>
<div class="field_with_errors">
    <input type="text" value="" name="article[title]" id="article_title">
</div>

Rails does this automatically for any fields that fail validation. You can use these classes to style invalid elements.

Note

The style rules that turn the invalid fields red are generated by the scaffold generator and are in app/assets/stylesheets/scaffolds.scss.

The formatted list of errors that appears at the top of the page is rendered using the following code snippet, which is a part of app/views/articles/_form.html.erb:
  <% if article.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(article.errors.count, "error") %> prohibited this article from being saved:</h2>
      <ul>
        <% article.errors.full_messages.each do |message| %>
          <li><%= message %></li>
        <% end %>
      </ul>
    </div>
  <% end %>

Now that you understand this, let’s submit the form with valid data. If all goes according to plan, the new article should be created, and you’re redirected to that article’s show action, where you see the friendly notice message you set. Notice that if you refresh the page using your browser’s Refresh button, the notice message disappears.

The edit and update Actions

The edit and update actions look almost identical to the new and create actions. The main difference is that instead of instantiating a new Article object, you fetch an existing one. This happens with a callback called before_action. This is similar to the Active Record callbacks we looked at in Chapter 6. In this case, the set_article method is called before the show, edit, update, and destroy actions are run. The set_article method loads the article using the id passed in params. This allows your code to stay DRY by keeping you from typing that line multiple times throughout the controller. It works exactly as if the code from the set_article method were typed at the very beginning of your action.

Looking at our action again, we used Active Record’s update method to update all the Article attributes with those from the article_params method. If the update fails, update returns false, and your if statement takes the else path (Listing 7-11).
# PATCH/PUT /articles/1
# PATCH/PUT /articles/1.json
def update
  respond_to do |format|
    if @article.update(article_params)
      format.html { redirect_to @article, notice: 'Article was successfully updated.' }
      format.json { render :show, status: :ok, location: @article }
    else
      format.html { render :edit }
      format.json { render json: @article.errors, status: :unprocessable_entity }
    end
  end
end
Listing 7-11

The Update Action in app/controllers/articles_controller.rb

Revisiting the Views

Let’s get back to the views. If you look at the new and edit templates, you can’t help but notice they render almost the same HTML: only the header and navigation are slightly different. Remember from the RESTful discussion that the HTTP request methods for create and update should be POST and PUT, respectively. Rails once more takes care of that for you. You’re rendering the same app/view/articles/_form.html.erb partial, but Rails knows the request method to use based on the @article variable passed to the form_with helper.

Try editing one of the articles. The URL should be something like http://localhost:3000/articles/1/edit; it looks similar to the new form, but with the record information already populated (Figure 7-5).
../images/314622_4_En_7_Chapter/314622_4_En_7_Fig5_HTML.jpg
Figure 7-5

Editing an existing article

Thanks to the form_with helper, the form fields are populated with their respective @article attributes. If you try to submit this form and look at the output from the server running on the command prompt, you’ll see the following:
Started PATCH "/articles/1" for ::1 at 2020-02-22 15:10:55 -0600
Processing by ArticlesController#update as HTML
  Parameters: {"authenticity_token"=>"QDD9QBMIUikwWl6NgIqpl2kjuRH0wcZiMqL+ltl/bTcK3MQC/SnjANd0MlLIrHAhPFwDgVyYtX7ZYgCvqqYpWw==", "article"=>{"title"=>"RailsConf2020", "location"=>"", "excerpt"=>"", "body"=>"RailsConf is the official gathering for Rails developers..", "published_at(1i)"=>"2020", "published_at(2i)"=>"2", "published_at(3i)"=>"18", "published_at(4i)"=>"01", "published_at(5i)"=>"17"}, "commit"=>"Update Article", "id"=>"1"}
  Article Load (0.3ms)  SELECT "articles".* FROM "articles" WHERE "articles"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
  ↳ app/controllers/articles_controller.rb:67:in `set_article'
   (0.1ms)  begin transaction
  ↳ app/controllers/articles_controller.rb:44:in `block in update'
  Article Update (0.6ms)  UPDATE "articles" SET "location" = ?, "excerpt" = ?, "published_at" = ?, "updated_at" = ? WHERE "articles"."id" = ?  [["location", ""], ["excerpt", ""], ["published_at", "2020-02-18 01:17:00"], ["updated_at", "2020-02-22 21:10:55.483973"], ["id", 1]]
  ↳ app/controllers/articles_controller.rb:44:in `block in update'
   (3.5ms)  commit transaction
  ↳ app/controllers/articles_controller.rb:44:in `block in update'
Redirected to http://localhost:3000/articles/1
Completed 302 Found in 12ms (ActiveRecord: 4.4ms | Allocations: 3742)

Notice the bold line: the update action of the articles controller was called as expected. Rails recognized that the article variable passed to form_with wasn’t a new record; therefore, it called the update action for you. This is yet another example of convention over configuration in Rails.

Staying DRY with Partials

A typical web application is rife with view code and often suffers from a lot of needless duplication. The HTML forms for adding and modifying articles are good examples of forms that are very similar. Wouldn’t it be nice if there were a way to reuse the common elements from one form in more than one place? That’s where partial templates come in.

Partial templates , usually referred to as partials, are similar to regular templates, but they have a more refined set of capabilities. Partials are used quite often in a typical Rails application, because they help cut down on duplication and keep the code well organized. They follow the naming convention of being prefixed with an underscore, thus distinguishing them from standard templates (which are meant to be rendered on their own).

Rather than creating two separate forms, Rails keeps your code DRY by using a single partial and including it from both the new and edit templates. Let’s look at the code from new.html.erb and edit.html.erb, shown in Listings 7-12 and 7-13, respectively.
<h1>New Article</h1>
<%= render 'form', article: @article %>
<%= link_to 'Back', articles_path %>
Listing 7-12

The app/views/articles/new.html.erb File

<h1>Editing Article</h1>
<%= render 'form', article: @article %>
<%= link_to 'Show', @article %> |
<%= link_to 'Back', articles_path %>
Listing 7-13

The app/views/users/edit.html.erb File

Let’s take a closer look at the render method. When referencing the partial in the render method, you don’t include the leading underscore:
<%= render 'form', article: @article %>

We see that two arguments are passed to the render method. The first argument is a string, and the second argument is a hash. (Have you noticed that Rails is a big fan of the options hash?)

The first argument is the partial’s name. Upon seeing this, the render method searches the current directory for a file named _form.html.erb. Notice that you don’t need to include the leading underscore or the file extension when specifying the partial’s name; Rails knows to look for a file in the same directory as the calling template with a leading underscore.

The second argument, article: @article, assigns the value of @article to a local variable in the partial named article. This isn’t strictly necessary—the form partial could have referenced @article directly instead of the article local variable. However, the scaffold generator chose to populate local variables in the template because many consider this a best practice; doing so minimizes the scope of the @article instance variable and arguably makes the partial more reusable. The next section explains in more detail.

Local Variable Assignment in Partials

The render method accepts a hash of local variables as part of the options hash. This is an example of what a render partial with local variables looks like:
<%= render 'header', title: 'My Blog' %>

Any number of local variables can be assigned this way, and any object can be set as the value. In the preceding example, the partial has access to the local variable title.

Rendering an Object Partial

Following the same convention of local variable assignment in partials, Rails makes it easier to render a partial that represents a specific object. For example, suppose you have the following render call in your code:
<%= render @article %>
Rails looks for a partial in app/views/articles/_article.html.erb and automatically assigns a local variable called article. It’s a shortcut for
<%= render 'articles/article', article: @article %>

Rendering a Collection of Partials

Another common pattern of rendering partials renders a collection of objects. Rails has a convention for rendering collections where you pass the collection as the first argument of the render method; Rails automatically loops across this collection and renders the partial of every object inside that array accordingly. Here’s an example:
  <%= render @articles %>
This behaves exactly like the previous call, but it performs more magic under the hood. For example, if the @articles array contains different Active Record objects, such as two articles and two comments, the render call renders the right partial template for each of those objects. It renders /app/views/comments/_comment.html.erb for the comment objects and /app/views/articles/_article.html.erb for the Article objects. It is roughly equivalent to (but more performant than) the following:
<% @articles.each do |object| %>
  <%= render object %>
<% end %>

Summary

This chapter covered a lot of ground. It began with a general introduction to the components that compose Action Pack, the Rails library responsible for the controller and the view. Then, it launched into a controller walk-through, where you visited your scaffold-generated controller. In doing so, you learned about routes, what happens when you generate a scaffold, how actions relate to views, and how to work with layouts. You were introduced to Rails’ form helpers, and you learned how easily forms integrate with Active Record objects. The chapter also introduced partials, and you learned how to keep your templates DRY and easy to maintain.

This chapter gave you your first taste of Rails outside the model. You now have a complete understanding of how Rails divides its concerns and a firsthand look at MVC in action. You started by modeling your domain in Chapters 5 and 6, and now you’ve completed the first iteration of building a web application around your domain.

You should be proud of yourself. At this stage, you know a lot about Rails. The next chapter builds on this knowledge, starting with more advanced topics like building a controller from scratch, sessions, and state and sprucing up the application with some CSS.