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 %}
Running:
.
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
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 %}
About
{% 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, "") %>
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") %>
Home
{% endhighlight %}Next, return to the About
view template at app/views/pages/about.html.erb
:
{% highlight ruby linenos %}
<% provide(title, "About") %>
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"
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 {% 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 - https://github.com/erikyuzwa/rails-static-pages