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.
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.
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.
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.
An Example View
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.
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.
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.
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.
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.
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
- 1.
Rails receives a request from the outside world (usually a browser).
- 2.
Routing picks apart the request to determine the controller and action to invoke.
- 3.
A new controller object is instantiated, and an action method is called.
- 4.
The controller interacts with a model (usually performing a CRUD operation in a database with an ActiveRecord model, but not necessarily).
- 5.
A response is sent back to the browser, in the form of either a render or a redirect.
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.
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.
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).
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.
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 |
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.
The config/routes.rb File: https://gist.github.com/nicedawg/3439fa09dc9be1f791271542308878fc
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
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.
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.
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)).
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.
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
_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.
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.
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.
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.
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.
Content of app/views/articles/new.html.erb
Content of app/views/articles/edit.html.erb
Content of app/views/articles/_form.html.erb
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.
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.
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 datetime_select helper is a FormHelper that outputs a set of HTML select tags to input a date and time value.
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).
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.)
Revisiting the Controller
The Create Action in app/controllers/articles_controller.rb
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.”
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.
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.
Rails does this automatically for any fields that fail validation. You can use these classes to style invalid elements.
The style rules that turn the invalid fields red are generated by the scaffold generator and are in app/assets/stylesheets/scaffolds.scss.
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.
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.
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).
The app/views/articles/new.html.erb File
The app/views/users/edit.html.erb File
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
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
Rendering a Collection of Partials
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.