3.2 Static Pages
With all the preparation from Section 3.1 finished, we’re ready to get started developing the sample application. In this section, we’ll take a first step toward making dynamic pages by creating a set of Rails actions and views containing only static HTML.5 Rails actions come bundled together inside controllers (the C in MVC from Section 1.3.3), which contain sets of actions related by a common purpose. We got a glimpse of controllers in Chapter 2, and will come to a deeper understanding once we explore the REST architecture more fully (starting in Chapter 6). In order to get our bearings, it’s helpful to recall the Rails directory structure from Section 1.3 (Figure 1.4). In this section, we’ll be working mainly in the app/controllers and app/views directories.
Recall from Section 1.4.4 that, when using Git, it’s a good practice to do our work on a separate topic branch rather than the master branch. If you’re using Git for version control, you should run the following command to checkout a topic branch for static pages:
$ git checkout -b static-pages
3.2.1 Generated Static Pages
To get started with static pages, we’ll first generate a controller using the same Rails generate script we used in Chapter 2 to generate scaffolding. Since we’ll be making a controller to handle static pages, we’ll call it the Static Pages controller, designated by the CamelCase name StaticPages. We’ll also plan to make actions for a Home page, a Help page, and an About page, designated by the lowercase action names home, help, and about. The generate script takes an optional list of actions, so we’ll include actions for the Home and Help pages directly on the command line, while intentionally leaving off the action for the About page so that we can see how to add it (Section 3.3). The resulting command to generate the Static Pages controller appears in Listing 3.6.
Listing 3.6: Generating a Static Pages controller.
Incidentally, it’s worth noting that rails g is a shortcut for rails generate, which is only one of several shortcuts supported by Rails (Table 3.1). For clarity, this tutorial always uses the full command, but in real life most Rails developers use one or more of the shortcuts shown in Table 3.1.6
Table 3.1: Some Rails shortcuts.
$ rails server
$ rails s
$ rails console
$ rails c
$ rails generate
$ rails g
$ rails test
$ rails t
$ bundle install
Before moving on, if you’re using Git it’s a good idea to add the files for the Static Pages controller to the remote repository:
$ git add -A $ git commit -m "Add a Static Pages controller" $ git push -u origin static-pages
The final command here arranges to push the static-pages topic branch up to Bitbucket. Subsequent pushes can omit the other arguments and write simply
$ git push
The commit and push sequence above represents the kind of pattern I would ordinarily follow in real-life development, but for simplicity I’ll typically omit such intermediate commits from now on.
In Listing 3.6, note that we have passed the controller name as CamelCase (so called because it resembles the humps of a Bactrian camel), which leads to the creation of a controller file written in snake case, so that a controller called StaticPages yields a file called static_pages_controller.rb. This is merely a convention, and in fact using snake case at the command line also works: the command
$ rails generate controller static_pages ...
also generates a controller called static_pages_controller.rb. Because Ruby uses CamelCase for class names (Section 4.4), my preference is to refer to controllers using their CamelCase names, but this is a matter of taste. (Since Ruby filenames typically use snake case, the Rails generator converts CamelCase to snake case using the underscore method.)
By the way, if you ever make a mistake when generating code, it’s useful to know how to reverse the process. See Box 3.1 for some techniques on how to undo things in Rails.
The Static Pages controller generation in Listing 3.6 automatically updates the routes file (config/routes.rb), which we saw briefly in Section 1.3.4. The routes file is responsible for implementing the router (seen in Figure 2.11) that defines the correspondence between URLs and web pages. The routes file is located in the config directory, where Rails collects files needed for the application configuration (Figure 3.1).
Figure 3.1: Contents of the sample app’s config directory.
Since we included the home and help actions in Listing 3.6, the routes file already has a rule for each one, as seen in Listing 3.7.
Listing 3.7: The routes for the home and help actions in the Static Pages controller.
Rails.application.routes.draw do get 'static_pages/home' get 'static_pages/help' root 'application#hello' end
Here the rule
maps requests for the URL /static_pages/home to the home action in the Static Pages controller. Moreover, by using get we arrange for the route to respond to a GET request, which is one of the fundamental HTTP verbs supported by the hypertext transfer protocol (Box 3.2). In our case, this means that when we generate a home action inside the Static Pages controller we automatically get a page at the address /static_pages/home. To see the result, start a Rails development server as described in Section 1.3.2:
$ rails server -b $IP -p $PORT # Use `rails server` if running locally.
Then navigate to /static_pages/home (Figure 3.2).
Figure 3.2: The raw home view (/static_pages/home).
To understand where this page comes from, let’s start by taking a look at the Static Pages controller in a text editor, which should look something like Listing 3.8. You may note that, unlike the demo Users and Microposts controllers from Chapter 2, the Static Pages controller does not use the standard REST actions. This is normal for a collection of static pages: the REST architecture isn’t the best solution to every problem.
Listing 3.8: The Static Pages controller made by Listing 3.6.
class StaticPagesController < ApplicationController def home end def help end end
We see from the class keyword in Listing 3.8 that static_pages_controller.rb defines a class, in this case called StaticPagesController. Classes are simply a convenient way to organize functions (also called methods) like the home and help actions, which are defined using the def keyword. As discussed in Section 2.3.4, the angle bracket < indicates that StaticPagesController inherits from the Rails class ApplicationController; as we’ll see in a moment, this means that our pages come equipped with a large amount of Rails-specific functionality. (We’ll learn more about both classes and inheritance in Section 4.4.)
In the case of the Static Pages controller, both of its methods are initially empty:
def home end def help end
In plain Ruby, these methods would simply do nothing. In Rails, the situation is different—StaticPagesController is a Ruby class, but because it inherits from ApplicationController the behavior of its methods is specific to Rails. Thus when visiting the URL /static_pages/home, Rails looks in the Static Pages controller and executes the code in the home action, and then renders the view (the V in MVC from Section 1.3.3) corresponding to the action. In the present case, the home action is empty, so all visiting /static_pages/home does is render the view. So, what does a view look like, and how do we find it?
If you take another look at the output in Listing 3.6, you might be able to guess the correspondence between actions and views: an action like home has a corresponding view called home.html.erb. We’ll learn in Section 3.4 what the .erb part means; from the .html part you probably won’t be surprised that it basically looks like HTML (Listing 3.9).
Listing 3.9: The generated view for the Home page.
<h1>StaticPages#home</h1> <p>Find me in app/views/static_pages/home.html.erb</p>
The view for the help action is analogous (Listing 3.10).
Listing 3.10: The generated view for the Help page.
<h1>StaticPages#help</h1> <p>Find me in app/views/static_pages/help.html.erb</p>
Both of these views are just placeholders: they have a top-level heading (inside the h1 tag) and a paragraph (p tag) with the full path to the corresponding file.
Solutions to exercises are available for free at railstutorial.org/aw-solutions with any Rails Tutorial purchase. To see other people’s answers and to record your own, join the Learn Enough Society at learnenough.com/society.
Generate a controller called Foo with actions bar and baz.
By applying the techniques described in Box 3.1, destroy the Foo controller and its associated actions.
3.2.2 Custom Static Pages
We’ll add some (very slightly) dynamic content starting in Section 3.4, but as they stand, the files shown in Listing 3.9 and Listing 3.10 underscore an important point: Rails views can simply contain static HTML. This means we can begin customizing the Home and Help pages even with no knowledge of Rails, as shown in Listing 3.11 and Listing 3.12.
Listing 3.11: Custom HTML for the Home page.
<h1>Sample App</h1> <p> This is the home page for the <a href="http://www.railstutorial.org/">Ruby on Rails Tutorial</a> sample application. </p>
Listing 3.12: Custom HTML for the Help page.
<h1>Help</h1> <p> Get help on the Ruby on Rails Tutorial at the <a href="http://www.railstutorial.org/help">Rails Tutorial help page</a>. To get help on this sample app, see the <a href="http://www.railstutorial.org/book"><em>Ruby on Rails Tutorial</em> book</a>. </p>
Figure 3.3: A custom Home page.
Figure 3.4: A custom Help page.