One of the most common starting points of a website or web application are pages that provide mostly unchanging content. These are often referred to as “static” pages.
There are usually three reasons for this; one, most web applications or sites are trying to build a connection with the visitor, and I’m not talking about the technical network connection. From the second you arrive at a website, the company or people behind it are trying to create a human connection with you. Secondly, most web applications / sites rely on communication with a database. While this communication is speedier than ever, Google has shown statistics in the past that the bounce rate (eg. visitors leaving your site) is proportional to the time it takes to load the starting home page. In other words, the longer it takes to load your website, the faster people are leaving it. The third reason, is that static pages are often used as “landing pages” - content that highlights some product or service that you want to attract attention to.
With that in mind, the focus of this tutorial is to go through the process of putting some static pages together in Rails 6.
I’m super excited to help you make this happen!
Assumptions & Goals
- You are on a system that has Ruby on Rails 6 setup and available to you
- We want to have our application start on a “default” Home page
Open your shell and head to your favorite project directory. Then let’s
rails new the project!
1 rails new rails-static-pages
Once Rails and the bundler finish setting up the new project, let’s get it committed to the
git repository that
Rails initializes for you.
1 2 3 cd rails-static-pages git add . git commit -m "initial commit"
NB: I may forget to write / mention it from time to time, but it’s *usually* a good idea to “sanity check” your
system configuration by running
bin/rails s before you do anything else, just to quickly verify your app loads
Now let’s get a welcome page going. Usually, you’re explaining your product, or your personal / company goals.
Let’s use the handy
rails generate to help us out.
NB: remember you can use
rails g as a shortcut for
1 rails g controller pages
Once the generation is finished, find
app/controllers/pages_controller.rb. By default, it’s an empty controller, so
let’s add a new action to handle our static page, called
1 2 3 4 class PagesController < ApplicationController def home end end
With an action in our controller defined, let’s create a view to match. You’ll notice that an
was created during the generation process. To match the view with our controller action, create a file
You can put anything in there…right now we just need to verify that the view we want is what we see.
1 <h1>Home Page!</h1>
creating the route
With the controller and view setup, let’s update Rails so that it can find it. Open up the
1 2 3 Rails.application.routes.draw do get "/home" => "pages#home end
You’re adding a url mapping here. This new mapping means that whenever your browser uses
/home, then Rails
can find the controller / view template you are trying to get to.
Let’s test it out!
start the server
Since we have a controller / view template configured, let’s see how it looks right now in the browser. From the root of your project folder:
1 bin/rails s
Open your browser to
http://localhost:3000/home. You should be able to confirm the words Home Page!!
adding an rspec test for this controller
With our proper
home page displaying correctly, let’s add a unit test for it! By default, Rails sets us up with
RSpec for handling tests.
test/controllers/pages_controller_test.rb. To help demonstrate, let’s create a unit test for the
home static page, but let’s start off making it “fail”.
The test itself should be empty (or have some default comments inserted by Rails), so let’s create:
1 2 3 4 5 6 class PagesControllerTest < ActionDispatch::IntegrationTest test "should get the home page" do get pages_home_url assert_response :success end end
NB: If you get a screen full of strange errors, it’s likely due to the fact that we haven’t created our database
yet. Go ahead and run
If all goes well, you should see some output like:
1 2 3 4 5 # Running: . 1 runs, 1 assertions, 0 failures, 0 errors, 0 skips
There’s some other timing information in there which will perhaps be slightly different from machine to machine, but
the important output is seeing that
1 assertions display - eg. test passed!
now we break the unit test
Just to help underscore how helpful test coverage is as your application grows, let’s change our url in the
file without updating the unit test.
1 get "/home" => "pages#home"
1 get "/marketing" => "pages#home"
Now run the unit tests again with
bin/rails test… what happens?
We get an error!
Imagine this app grows over time, and has over 50 URL mappings. Not all of them would be to static pages, but just 50+ route mappings in general. How will you be able to keep track of which ones are still active, and which ones are not used at all anymore?
adding a root Route
With our static pages configured, there’s the question of what Rails refers to as the
root Route. This is usually
the default index page of your application or website that is displayed when you visit the website - in our specific
case, this would be the “default” page that we want shown when we hit
Let’s go back into
config/routes.rb and add an entry for
1 2 3 4 5 6 Rails.application.routes.draw do get "/home" => "pages#home # define our root / default route root "pages#home" end
In other words, we’re creating another
url mapping for the default / root Route.
Now open your browser, and head to
http://localhost:3000. Instead of the familiar “Yay! You’re on Rails!” page,
Rails will take you to
Let’s update our test coverage!
Go back into
test/controllers/pages_controller_test.rb, and add a new unit test for
1 2 3 4 test "root route should get the home page" do get root_url assert_response :success end
Are we done? Not quite.
Where’s the flaw in our testing strategy? Hint: content
Our unit tests are able to determine if the url in question resolves, but not that we’ve got the correct page contents.
How do we do this?
One way is to make use of some special ruby functions,
yield. But to REALLY help illustrate how handy they
are, we’re going to quickly add another static page,
adding an About static page
This is straight repetition of what we already did for the
Home static page, so this should take no time at all.
For a good challenge, stop reading right here and try adding it for yourself (don’t forget the new unit test!).
Back? Okay, let’s do a recap.
1 2 3 4 5 6 7 8 9 class PagesController < ApplicationController # Action to handle the About view def about end # Action to handle the Home view def home end end
Let’s add a new page for the
Next, we update the
1 2 3 4 5 6 7 Rails.application.routes.draw do get "/about" => "pages#about" get "/home" => "pages#home" # define our root / default route root "pages#home" end
Finally, update the
1 2 3 4 test "should get the about page" do get about_url assert_response :success end
Phew. Not too bad at all, considering we added a brand new route!
setting up provide and yield (and title)
Our strategy is to update the actual document
<title></title> element within each view. This will help us greatly when updating
our tests to confirm the page we want is the page we get.
First, let’s update our main application layout file,
1 2 3 4 5 6 <% provide(:title, "") %> <!DOCTYPE html> <html> <head> <title><%= yield(:title) %></title> *snip*
The key updates here is to add the
provide call at the top of the page. Next, we’re going to update the
section to call
Next, go back to your
Home view template at
1 2 <% provide(title, "Home") %> <h1>Home</h1>
Next, return to the
About view template at
1 2 <% provide(title, "About") %> <h1>About</h1>
Finally, let’s go back to our unit tests and update them to test the
<title> elements within each request:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class PagesControllerTest < ActionDispatch::IntegrationTest test "should get the about page" do get about_url assert_response :success assert_select "title", "About" end test "should get the home page" do get home_url assert_response :success assert_select "title", "Home" end test "root route should get the home page" do get root_url assert_response :success assert_select "title", "Home" end end
We went through quite a bit of steps here. To recap, we updated the main application layout file, to
title string within each view. Then we went into our 2 views, and just made sure to specific a different
title for each one -
Lastly, we updated the unit tests to call
assert_select to query our
title element within each resulting page
to make sure that the
title element we’re expecting, is the one we’re getting.
Go ahead and run
bin/rails test to verify everything.
You can find the code for this project on my github - https://github.com/erikyuzwa/rails-static-pages