Webpages Adding a Page to the App

In this demonstration, I will show how to add a webpage to an existing Rails web app.

General Steps

In general, the steps for adding a webpage to an existing Rails-based web app are as follows. To understand these steps, you will need to understand the deets on the Rails MVC architecture.

Creating the Billy Books Home Page

To demonstrate the steps for adding a webpage, we will be making a home page for an online bookstore called Billy Books. Figure 1 shows what the webpage will look like.

A web page that displays the address and store hours of a bookstore called Billy Books.

Figure 1. The Billy Books home page.

We will start with the main base app, which does not have any webpages initially, and we will add this webpage to the app.

Base App Code

Step 1 Add a Route

In Rails, routes specify how the web server will handle different sorts of HTTP requests. Thus, we must create a route that tells the web server how to handle requests for the Billy Books home page.

Routes are declared in the file, config/routes.rb, which contains only an empty block initially:

Rails.application.routes.draw do
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end

Substep Specify the HTTP request pattern to match for the route. To begin our route declaration, we add the part that tells the web server which HTTP requests will be for the home page by adding this code to the block:

Rails.application.routes.draw do

  get 'home'

end

The get part specifies that requests for the home page must have the HTTP GET verb. The 'home' part specifies that requests for the home page must have home a their resource path (e.g., as in the URL, http://localhost:3000/home).

Substep Specify the controller action to handle requests. Next, we add to our route which controller action should be called if an HTTP request matches the pattern:

Rails.application.routes.draw do

  get 'home', to: 'pages#home'

end

The to: argument above is a string that specifies the controller class and action method. The # is a separator character, with the controller class name on the left and the class’s action method name on the right. The pages bit is shorthand for the class name PagesController (i.e., the snake_case version of the class name, which is pages_controller, with the _controller part omitted). The home bit specifies to a public method of PagesController named home. Note that the PagesController class has not yet been created, and we will do so later in this demo.

Substep Set the prefix for the path/URL helpers. As a final addition to our route, we add a prefix for the Rails-generated path and URL helper methods:

Rails.application.routes.draw do

  get 'home', to: 'pages#home', as: 'home'

end

If an (optional) as: argument is specified for a route, Rails will generate two helper methods, a path helper and a URL helper. Later, we may need to use the relative path or full URL for this route in our code. For example, we may want to create a hyperlink to the home page. Hard coding such paths as strings makes code brittle—any change to the path would require finding and changing everyplace the path was used, a tedious and error-prone process. Thus, Rails provides path/URL helper methods for us to use instead of hard-coded strings. By specifying the prefix argument as: 'home', Rails will automatically generate a home_path and a home_url helper method for this route.

Test It!

To confirm that we made this change correctly, we run the following command in the terminal:

rails routes -E

The command should output a long list of routes, but the very first one is the only one we care about. If we coded our route correctly, it should look like this:

--[ Route 1 ]-----------------------------------------------
Prefix            | home
Verb              | GET
URI               | /home(.:format)
Controller#Action | pages#home
--[ Route 2 ]-----------------------------------------------
…

If we made an error, something different will be outputted. For example, if we made a syntax error, it would instead produce an error message.

Step 1 Changeset

Step 2 Create a Controller

In Rails, a controller class is responsible for handling the requests matched by a particular route. In the previous step, we specified in our route that a PagesController controller class would handle requests for the home page. Since PagesController does not yet exist, in this step, we will create it.

In general, we use the rails command to generate new controller classes. To generate our PagesController controller class, we run the following command:

rails generate controller Pages

The rails generate controller part of the above command specifies that the command will generate a controller class (along with some supporting files/directories). The Pages argument specifies that the name of the controller class will be PagesController. Note that the name given to this command (Pages) is in UpperCamelCase (following the convention for class names in Ruby) and the Controller part of the name is omitted.

This command should output a list of everything it generated:

Running via Spring preloader in process 15430
      create  app/controllers/pages_controller.rb
      invoke  erb
      create    app/views/pages
      invoke  test_unit
      create    test/controllers/pages_controller_test.rb
      invoke  helper
      create    app/helpers/pages_helper.rb
      invoke    test_unit
      invoke  assets
      invoke    scss
      create      app/assets/stylesheets/pages.scss

Test It!

Although there’s no good way to test this step per se, we can verify that we generated the code correctly by carefully inspecting the output of the command. In particular, look closely at the first create line:

create  app/controllers/pages_controller.rb

The name of the controller file generated should exactly match pages_controller.rb. If there is any difference in spelling, capitalization, or punctuation, then an error was made.

If we discover an error in the file name, we can undo the previous rails generate controller command by running rails destroy controller; however, we will need to specify the name of the controller exactly as we did before (i.e., using an incorrect name). One way to accomplish this is to click the up-arrow key to get back to our previous rails generate controller command. Then, we edit the command to replace generate with destroy, and run the command.

For example, imagine that we accidentally ran this incorrect rails generate controller command:

rails generate controller OopsWrongName

We can effectively undo the command by running this command:

rails destroy controller OopsWrongName

Step 2 Changeset

Step 3 Create a Controller Action

In Rails, a controller action method defines how requests matched by a particular route are processed. We previously specified in our route that a home controller action would process requests for the home page, and in this step, we will create that action.

We will add the action method to the PagesController class defined in the file app/controllers/pages_controller.rb. Currently, the file looks like this:

class PagesController < ApplicationController
end

Substep Add an empty action method. We add a home action (empty for now) to the controller by defining this public method home in the body of the PagesController class:

class PagesController < ApplicationController

  def home

  end

end

Substep Make the action render the view template. We make the home action render a view template for the webpage by filling in the body of the home method with the following render command:

class PagesController < ApplicationController

  def home
    render :home
  end

end

The render method uses a view template to create a full response, including HTML code, to send back to the browser. The :home part is a symbol that tells Rails to render the view template in app/views/pages/home.html.erb. Rails automatically infers the pages subdirectory, because the call to render is being made inside the PagesController class. Rails automatically infers the home.html.erb view template from the :home symbol name. Note that the app/views/pages/home.html.erb view template does not exist yet, and we will create it in the next step.

Test It!

To test that this step was completed correctly, we run the web app (as per the steps in the running apps demo), and we open the URL http://localhost:3000/home in our web browser.

At the top of the webpage, the error message, “Template is missing” should appear. The next line should begin with “Missing template pages/home…”. These error messages tell us that our controller action is working, and the only problem is that the view template has not yet been created.

If different error messages appear, such as “SyntaxError” or “NoMethodError”, we may have made a mistake in our code. To debug our error, we must carefully inspect our code for any discrepancy with the above code. Note that error messages may also be caused by mistakes in how we run the app, so we may need to revisit those steps if there is no apparent error in our controller action code.

Step 3 Changeset

Step 4 Create a View Template

In Rails, view templates are used to define how a webpage will look, and they are commonly used to generate HTML. In the previous step, our home controller action specified that the view template for the home page would be app/views/pages/home.html.erb. Thus, we will now create view template.

We first create an empty HTML.ERB view template by making a new file called home.html.erb in the app/views/pages/ directory. We can create this file using VS Code or using the touch command (run from the top-level project folder), like this:

touch app/views/pages/home.html.erb

Then, we define what the web page will look like by filling in the file with the following HTML code:

<h1>Welcome to Billy Books!</h1>

<p>
  Come visit us at 7107 Juniper Road Fairbend, TN, 37062!
</p>

<p>
  Store Hours:
</p>

<ul>
  <li>Monday: 10am - 7pm</li>
  <li>Tuesday: 10am - 7pm</li>
  <li>Wednesday: 10am - 7pm</li>
  <li>Thursday: closed</li>
  <li>Friday: 10am - 7pm</li>
  <li>Saturday: 12pm - 6pm</li>
  <li>Sunday: closed</li>
</ul>

If you aren’t familiar with these HTML tags, read the deets on common HTML tags.

Test It!

To test that this step was completed correctly, we run the web app (as per the steps in the running apps demo), and we open the URL http://localhost:3000/home in our web browser. The webpage displayed should look exactly like Figure 1.

If an error message is displayed, then we may have made an error in how we named the view template file or in which directory we saved the view template. We may also have made in an error in how we ran the app.

If the webpage opens, but parts of it do not look right, we likely made an error in our HTML code.

Step 4 Changeset

Conclusion and Further Reading

Following the above steps, we have now added a home page to an otherwise empty web app.

Demo App Code

Here are some links to additional documentation on the topics covered in this demo: