LearnCreating Static Pages in Ruby on Rails

Jason Seifer
writes on May 27, 2015

Roll Your Own Static Pages in a Rails App

Have you ever wanted to create static pages in a Rails application? These are pages which don’t necessarily contain any dynamic info or pull from the database, and don’t require an entire controller. There are some pre-built gems that allow this to be done fairly quickly, but it’s also good for practice to roll your own. Let’s see how we can create some static pages in our own fresh Rails application.

Table of Contents

Setup

For the rest of this tutorial, I’m going to be using a freshly generated Rails 4.2 application. The rest of these instructions should work in other versions of Rails but I’ve only tested against the latest version. If you’d like to follow along, install the latest version of Ruby and Rails and skip ahead. If you don’t have Ruby and Rails installed, there are some great tutorials for OS X, Windows, and Ubuntu over on Treehouse that will get you up and running.

Generate a Pages Controller

Since we’re doing static pages only, we don’t need to generate any models to interface with a database. You can either create a controller yourself or use Rails to generate one. Either way, we’ll skip creating the CSS and JavaScript that go along with it. If you’d like to use Rails to generate a controller, run this command:

bin/rails generate controller pages --skip-assets

Alternatively, just create it yourself using the command line:

touch app/controllers/pages_controller.rb

And place the following in the app/controllers/pages_controller.rb file:

  class PagesController < ApplicationController
    def show
    end
  end  

That will set up an empty show action in our controller. The show action in the pages controller will be what we use to render our static page.

Now that we have a show action, we need to make it do something. We’re going to tell the show action to render a page template that is the same name as a parameter that is passed in. We’re going to call the parameter page. We’re going to assume that the static page lives in the app/views/pages directory and has an extension of html.erb. Rails looks for that extension to render automatically, so we can leave it off. Our show action will now look like this:

class PagesController < ApplicationController
  def show
    render template: "pages/#{params[:page]}"
  end
end

With the show action all set up, we can move on to the routes.

Create a Route

The route is really easy and is just a single entry in our routes.rb file:

Rails.application.routes.draw do
  get "/pages/:page" => "pages#show"
end

This will send every url that matches /pages/ to our pages controller we created above. Any of the following would now work:

  • /pages/about
  • /pages/home
  • /pages/features

Based on the controller we created above, we now have to place our static pages in the app/views/pages directory and they will show up.

Create a Static Page

With the above all set up, creating the static page is very easy. Just create the file in your terminal (or text editor):

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

Now fill it with some content. I’ve chosen to use some cupcake ipsum text because cupcakes are delicious. Save the file and head over to http://localhost:3000/pages/about and you should see the following:

about page

It works! Awesome! This is a great start.

A Static Home Page

It may be a requirement for your application to have a static home page with no dynamic content. That’s simple to add to our current setup. First, we’ll need to create the home page.

Place the following in app/views/pages/home.html.erb.


  <h2>Home Page</h2>

  <p>This would be a static home page in a Rails application.</p>

This is just a place holder. Your real content can go in there later. Next, we’ll tell Rails to look for that as the default root page. We do that by passing in the page parameter to the root route directive. Now we just have to add the following to config/routes.rb, just before the closing end keyword:

root "pages#show", page: "home"

Now when you go to http://localhost:3000 you should see the following:

Static Rails Home Page

If you see the following screen, you may have named it something other than app/views/pages/home.html.erb:

default rails home

Double check that for errors and reload the page.

Handling Not Found Errors

We have basic static page rendering set up but we haven’t planned for what happens when someone hits a page that doesn’t exist. We need to tell the visitor that the page is not found, and we’d be good net citizens to return a 404 status code as well. We can handle all of this in the pages controller.

In order to do all of that, we’ll create a method called valid_page? that checks to make sure the page actually exists in our application where we expect it to. The method exist? on the File class will return true or false if the file actually exists in that spot in the file system. We’ll pass that method an instance of the PathName class which has the full path of the requested template file on disk. The whole method will return true or false if the file exists.

From there, all we need to do is render a not found page if the file doesn’t exist. A default Rails application will have a 404 page in the public directory, so we can just use that. We’ll also send down a 404 status with the :not_found symbol. Here’s what the pages controller now looks like:

class PagesController < ApplicationController
    def show
      if valid_page?
        render template: "pages/#{params[:page]}"
      else
        render file: "public/404.html", status: :not_found
      end
    end

    private
    def valid_page?
      File.exist?(Pathname.new(Rails.root + "app/views/pages/#{params[:page]}.html.erb"))
    end
  end

Now if we go a nonexistent page, we should see the following:

404 Static Rails Page

Static Pages, Slightly Enhanced

The static pages are now all set up but we’ve decided to throw some marketing pages in to show off some of our application’s features. Marketing wants us to put these at /pages/features/one, /pages/features/two, and so on. This is easy enough and only requires a small change in our code. Open up the routes and change this:

get "/pages/:page" => "pages#show"

To this:

get "/pages/*page" => "pages#show"

That small change will pass the page parameter in as an array. We can now create a features directory in app/views/pages and place our new feature pages in there. Here’s an example of features/one:

First Feature Image

One more neat thing is that we have access to Ruby’s methods in these pages. We don’t want to go crazy, but a few little calls here and there aren’t too much of an issue. For example, if we wanted to add the current year to our home page, we could place the following in the page:

<p>© <%= Date.today.year %> My App.</p>

Which would render the following:

Static home with year

Further Reading

This is just one quick way to implement your own static pages in a Rails application. I also recommend checking out high_voltage by Thoughtbot. That gem provides a Rails engine to get up and running with static pages quickly and provides some helper methods as well. What do you do for static pages? Let us know in the comments or drop me a tweet.

20 Responses to “Creating Static Pages in Ruby on Rails”

  1. Great post and I used it. Thanks for sharing it.

  2. Fogive me for the stupid question, but what is an example of dynamic content on a home page?
    If static pages are not supposed to make database calls, however isn’t a returning user signing in on the home page with it’s credentials stored in the database breaking this rule?
    Feel free to scathingly correct me, I’m waiting…

  3. Handling Not Found Errors.
    I handle this in a different way. In the routes file, I have as the last entry
    get ‘*path’ => ‘application#routing_error’

    In the application controller I have
    def routing_error
    render template: ‘404’
    end

    My 404 file just sits in /views

  4. Rafael Oliveira on February 11, 2017 at 6:19 pm said:

    I’d rather use
    `template_exists?` (as suggested by Gregor)
    AND
    `raise ActionController::RoutingError.new(“No route matches [GET] \”pages/#{params[:page]}\””)`

    Instead of
    `File.exist?`
    `render file: “public/404.html”, status: :not_found`

  5. How can i set up a link in app/views/pages/home.html.erb which would go to app/views/pages/about.html.erb

  6. Hi!

    I’m using minitest to test rather than rspec and I’m new!

    My controller test still works to test bringing back the home page if I do :home, how do I write a test for :about? Essentially this test:

    test “should get about” do
    get :about
    assert_response :success
    end

    Gets this error: ActionController::UrlGenerationError: ActionController::UrlGenerationError: No route matches {:action=>”about”, :controller=>”welcome”}

  7. TeTiRoss on April 8, 2016 at 5:38 am said:

    @neymarsabin, you can just write smth like this:

  8. How do i define the link_to pattern in other pages as we dont know what are the routes??

    • TeTiRoss on April 8, 2016 at 5:39 am said:

      you can just write smth like this: link_to “End page”, “/pages/end_page”

      • When I tried this – it only worked as long as I wasn’t already viewing another /pages/page

        So for example, I would start from home and goto a link for /pages/terms (for terms of service) which is in my footer. I also have a pages/privacy page for privacy policy.

        The problem is if I click on /pages/terms and then click on the privacy link, it turns it into /pages/pages/terms – which isn’t valid – there’s an extra pages in there! 🙂

        • Jeff:

          You may have already figured this out, but for anyone that runs into this issue later on, the reason for this is your link was relative to your current path.

          If you are using (note the path does *not* start with a slash), when you come from some url at your site, for example:

          mywebsite.com/pages/my_other_page

          then your link_to will replace the current page of the url, but not the current folder, and then it will append pages/my_page to the url you’re currently at and you’ll end run into the problem you mentioned you were having, where you end up at some url like:

          mywebsite.com/pages/pages/my_page

          On the other hand, if you use (note the path *does* start with a slash), regardless of what page you were coming from, you will be linked to:

          mywebsite.com/pages/my_page

          Hope that helps!

          • Apparently it didnt like the example urls I was giving in some spots, Im not sure if it thought I was spamming with links to a website or something, but now the post reads funny and I can’t edit it.

            So just to quickly summarize what I was saying:

            When using the link_to helper, if your path starts with a slash, it is an absolute path and you will not have the issue. The url will be mywebsite/path, for whatever path you specify.

            If you do not use a slash, the link will be relative, and will replace the current page, but not the folder (controller), in the url, so you’ll end up with a duplicate folder in the url, which is the issue you were having. For example, if you were at the url mywebsite/pages/some_page, and the path of your link_to helper was ‘pages/some_other_page’, you would end up at the url mywebsite/pages/pages/some_other_page.

            Hope that helps!

  9. Of course this blog isn’t finished, but it is a working Rails application. Some things to consider are giving it some style with CSS, formatting with RedCloth or similar, adding real authentication with Devise, etc.

  10. Thanks for sharing. You could just use template_exists? “pages/#{params[:page]}” instead of File.exist?. Cheers

  11. Rails is such an amazing thing for developing applications rapidly.

  12. Francesco on May 27, 2015 at 4:54 pm said:

    These are pseudo static pages though. Most of all, they don’t take any advantage of a static page: hit rails router, controller and even ruby inside the page. Either put in there some STRONG caching mechanisms or make something different, because these are just dynamic pages not interacting with the database. A static homepage usually is made to reduce database pressure or rails server pressure, so either cache a static html page every x hours and serve it from apache/nginx or rename the article because I believe it’s deceiving less experienced people

    • Great article.

      The author here is not using the term static in the technical programming taxonomy, rather in the sense timeless vs scheduled or with potential expiration. If one were to pick at the technical nuances of static, even plain html doesn’t present itself, it is dynamically delivered, styled, and displayed. But, of course, no one is thinking about those meanings of static vs dynamic.

Leave a Reply

Learn to code with Treehouse

Start your 7 day free trial today and get access to hundreds of video courses in web development, design and business!

Learn more