Building Static Content Pages in Rails6

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

Getting Started

Open your shell and head to your favorite project directory. Then let's rails new the project!

{% highlight ruby linenos %} rails new rails-static-pages {% endhighlight %}

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.

{% highlight ruby linenos %} cd rails-static-pages git add . git commit -m "initial commit" {% endhighlight %}

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 ok.

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 rails generate

{% highlight ruby linenos %} rails g controller pages {% endhighlight %}

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 home.

{% highlight ruby linenos %} class PagesController < ApplicationController def home end end {% endhighlight %}

With an action in our controller defined, let's create a view to match. You'll notice that an app/views/pages folder was created during the generation process. To match the view with our controller action, create a file app/views/pages/home.html.erb.

You can put anything in there...right now we just need to verify that the view we want is what we see.

{% highlight ruby linenos %}

Home Page!

{% endhighlight %}

creating the route

With the controller and view setup, let's update Rails so that it can find it. Open up the config/routes.rb:

{% highlight ruby linenos %}

Rails.application.routes.draw do get "/home" => "pages#home end {% endhighlight %}

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:

{% highlight ruby linenos %}

bin/rails s {% endhighlight %}

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.

Navigate to 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:

{% highlight ruby linenos %}

class PagesControllerTest < ActionDispatch::IntegrationTest test "should get the home page" do get pageshomeurl assert_response :success end end {% endhighlight %}

Now run bin/rails test.

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 bin/rails db:migrate

If all goes well, you should see some output like:

{% highlight ruby linenos %}



1 runs, 1 assertions, 0 failures, 0 errors, 0 skips

{% endhighlight %}

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 config/routes.rb file without updating the unit test.

Change: {% highlight ruby linenos %} get "/home" => "pages#home" {% endhighlight %} To: {% highlight ruby linenos %} get "/marketing" => "pages#home" {% endhighlight %}

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 http://localhost:3000.

Let's go back into config/routes.rb and add an entry for root:

{% highlight ruby linenos %}

Rails.application.routes.draw do get "/home" => "pages#home

# define our root / default route
root "pages#home"

end {% endhighlight %}

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 pages#home.

Let's update our test coverage!

Go back into test/controllers/pages_controller_test.rb, and add a new unit test for root_url:

{% highlight ruby linenos %}

test "root route should get the home page" do get rooturl assertresponse :success end {% endhighlight %}

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, provide and yield. But to REALLY help illustrate how handy they are, we're going to quickly add another static page, About.

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.

app/controllers/pages_controller.rb: {% highlight ruby linenos %}

class PagesController < ApplicationController # Action to handle the About view def about end

# Action to handle the Home view
def home

end {% endhighlight %}

That's the PagesController.

Let's add a new page for the HTML template, app/views/pages/about.html.erb:

{% highlight ruby linenos %}


{% endhighlight %}

Next, we update the config/routes.rb file: {% highlight ruby linenos %}

Rails.application.routes.draw do get "/about" => "pages#about" get "/home" => "pages#home"

# define our root / default route
root "pages#home"

end {% endhighlight %}

Finally, update the PagesControllerTest in test/controllers/pages_controller_test.rb: {% highlight ruby linenos %}

test "should get the about page" do get abouturl assertresponse :success end {% endhighlight %}

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, app/views/layouts/application.html.erb: {% highlight ruby linenos %}

<% provide(:title, "") %>

<%= yield(:title) %> *snip* {% endhighlight %}

The key updates here is to add the provide call at the top of the page. Next, we're going to update the <title> section to call yield(:title).

Next, go back to your Home view template at app/views/pages/home.html.erb: {% highlight ruby linenos %}

<% provide(title, "Home") %>


{% endhighlight %}

Next, return to the About view template at app/views/pages/about.html.erb: {% highlight ruby linenos %}

<% provide(title, "About") %>


{% endhighlight %}

Finally, let's go back to our unit tests and update them to test the <title> elements within each request: {% highlight ruby linenos %}

class PagesControllerTest < ActionDispatch::IntegrationTest

test "should get the about page" do
    get about_url
    assert_response :success
    assert_select "title", "About"

test "should get the home page" do
    get home_url
    assert_response :success
    assert_select "title", "Home"

test "root route should get the home page" do
    get root_url
    assert_response :success
    assert_select "title", "Home"

end {% endhighlight %}

We went through quite a bit of steps here. To recap, we updated the main application layout file, to yield() any given title string within each view. Then we went into our 2 views, and just made sure to specific a different title for each one - Home and About.

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 -

If you found this tutorial helpful, please share it!

About the author

Hey, I'm Erik, a software engineer, gamer, writer, and content creator. I publish articles and tutorials about modern software development, design, and programming.

Get the newsletterBuy me a coffee