Static pages in Rails?
There are a variety of approaches you can take (they're not all good approaches).
1 - public
directory
If it's truly static, you can put it in the public
directory. Things in the public
directory will be served immediately, without going through the Rails stack.
Advantages:
- Because it doesn't have to waste time going through the Rails stack, the client will receive a faster response.
Disadvantages:
- You won't be able to use your sites layout. Or view helpers like
link_to
. - Instead of your views being in one place (
app/views
), now they're in two places (app/views
andpublic
). This can be confusing.
Thoughts: I feel pretty strongly that the disadvantages outweigh the advantages here. If you're looking to make a minor improvement in speed at the expense of readability and programmer happiness, why use Rails in the first place?
2 - Place in app/views
and render directly from the Router
It is possible to render views from the router. However, it definitely isn't The Rails Way.
From the official RailsGuide on routing:
1 The Purpose of the Rails Router
The Rails router recognizes URLs and dispatches them to a controller's action.
Architecturally, there isn't anything inherently wrong with having a router map directly to a view. Many other frameworks do just that. However, Rails does not do that, and deviating from an established convention is likely to confuse other developers.
like should I create a controller or not?
Unless you want to take one of the approaches mentioned above - yes, you should create a controller.
The question then becomes what to name the controller. This answer outlines some options. I'll list them here with some thoughts. I'll also add three other options.
3 - Use ApplicationController
# routes.rb
get "/about" to: "application#about"
# application_controller.rb
class ApplicationController < ActionController::Base
def about
render "/about"
end
end
# app/views/about.html.erb
The advantage here is that you don't introduce overhead/bloat by creating a new controller and folder. The disadvantage is that it's not The Rails Way. Every controller you create inherits from ApplicationController
. ApplicationController
is typically used to house functionality that you want to share between all other controllers. See this example from the Action Controller Overview Rails Guide:
class ApplicationController < ActionController::Base
before_action :require_login
private
def require_login
unless logged_in?
flash[:error] = "You must be logged in to access this section"
redirect_to new_login_url # halts request cycle
end
end
end
4 - StaticController
or StaticPagesController
Michael Hartl's popular Ruby on Rails Tutorial uses a StaticPagesController
. I agree with the source I got this from in that I don't like this approach because the pages often aren't actually static.
Also, there is a possibility of confusion - why did we put other static views in separate controllers? Shouldn't static views be rendered from the StaticPagesController
? I don't think the possibility of confusion is too high, but still wanted to note it.
Also note Hartl's footnote:
Our method for making static pages is probably the simplest, but it’s not the only way. The optimal method really depends on your needs; if you expect a large number of static pages, using a Static Pages controller can get quite cumbersome, but in our sample app we’ll only need a few. If you do need a lot of static pages, take a look at the high_voltage gem. ↑
5 - PagesController
The official Ruby on Rails routing guide uses PagesController
. I think this approach is fine, but it isn't descriptive at all. Everything is a page. What distinguishes these pages from the other pages?
6 - UncategorizedPagesController
I would call the controller UncategorizedPagesController
, because that's exactly what they are - uncategorized pages. Yes, it's a little more cumbersome to type and read. I prefer the advantage of clarity over conciseness, but I could understand the choice to be more concise and go with PagesController
, or something else.
7 - High Voltage gem
With High Voltage, you don't have to do the tedious work of writing out routes and empty controller actions:
# routes.rb
root 'pages#home'
get '/about', to: 'pages#about'
get '/contact', to: 'pages#contact'
get '/help', to: 'pages#help'
get '/terms-of-service', to: 'pages#terms_of_service'
get '/landing-page', to: 'pages#landing_page'
...
# pages_controller.rb
def PagesController < ApplicationController
def home
end
def about
end
def contact
end
def help
end
def terms_of_service
end
def landing_page
end
...
end
You just add your pages to app/views/pages
and link to them: <%= link_to 'About', page_path('about') %>
.
Static pages in Ruby on Rails
Depends on how you want to handle the content in those pages.
Approach #1 - store content in views
If you just want to put all your content in ERB views, then a very simple approach is to create a PagesController
whose purpose is to deal with static pages. Each page is represented by one action in the controller.
pages_controller.rb:
class PagesController < ApplicationController
def home
end
def about
end
def contact
end
end
routes.rb:
match '/home' => 'pages#home'
match '/about' => 'pages#about'
match '/contact' => 'pages#contact'
Then create home.html.erb, about.html.erb, and contact.html.erb views under app/views/pages. These views contain whatever content you want on your static pages. They'll by default use your app's application.html.erb layout.
You'll also want to look into page caching to give yourself a boost in performance.
Approach #2 - store content in database
Another approach I've used is to make a very basic CMS for static pages. In this case, pages are represented in the model. It uses the friendly_id gem to handle slugs for each page so that they can be retrieved by a pretty name in the URL (e.g., /about) rather than by ID.
page.rb:
class Page < ActiveRecord::Base
attr_accessible :title, :content
validates_presence_of :title, :content
has_friendly_id :title, :use_slug => true, :approximate_ascii => true
end
pages_controller.rb:
class PagesController < ApplicationController
def show
@page = Page.find(params[:id])
render 'shared/404', :status => 404 if @page.nil?
end
end
show.html.erb:
<%= raw @page.content %>
routes.rb:
match '/:id' => 'pages#show'
Note: put this entry at the end of routes.rb since it matches everything.
Then how you want to create, edit and update pages are up to you - you can have an admin interface, or build it in to your public interface somehow. This approach can benefit from page caching too.
Static pages to ruby on rails
Start with a single model and controller for companies. Create a index
method inside the app/controllers/companies_controller
. Then create the content inside file app/views/companies/index.html.erb
to check that everything works, for example:
<h1> Hi! This is root page and index method in CompaniesController! </h1>
In config/routes.rb
, you must specify a plural name for companies
if you plan to create and process more than one, and leave it as it is, if the entity is the only one company for this project. Set plural name for this resource for this moment to create standard routes for CRUD:
resources :companies
root to: "companies#index"
More about routes you can find in rails guide.
You can try using the built-in scaffold generator in order to quickly generate the application skeleton:
rails generate scaffold companies
The command above will generate controller, model, views and routes with CRUD methods in controller and views for the controller methods. Each view in app/views/"resource_name_plural"
adjusted with method in controller in config/routes.rb
file. This is how the MVC pattern works.
If you want to create static pages, maybe you should look at the high_voltage gem.
Rails: How to link to static pages
in your routes.rb you should have something like
get '/page', to: 'path#page', as: :page
where path is the folder where the page file is in
eg
get '/page', to: 'layout#page', as: :page
then you will link with
<li><%= link_to "page", page_path %>
Rails Tutorial static pages routes test red (5.28)
Your test/controllers/static_pages_controller_test.rb have problem. I would suggest to replace it with below contents.
require 'test_helper'
class StaticPagesControllerTest < ActionDispatch::IntegrationTest
test "should get home" do
get root_path
assert_response :success
assert_select "title", "Ruby on Rails Tutorial Sample App"
end
test "should get help" do
get help_path
assert_response :success
assert_select "title", "Help | Ruby on Rails Tutorial Sample App"
end
test "should get about" do
get about_path
assert_response :success
assert_select "title", "About | Ruby on Rails Tutorial Sample App"
end
test "should get contact" do
get contact_path
assert_response :success
assert_select "title", "Contact | Ruby on Rails Tutorial Sample App"
end
end
Change the above file as I have suggested and run $ rails test
you can see green test. I also suggest you to upgrade your app to rails 5.0.0 as Michael Hartl's have been upgraded his rails tutorials to rails 5.0.0 in future you have more things to learn and if you upgrade it, your journey of learning would be more error free and pleasant.
Link_to for static pages
For static pages you should check out high_voltage gem. Once it's installed, it'll make a folder pages
inside your view directory and it'll generate a named route method of page_path
. For example, if you create a static page pages/static
then you can refer it to by page_path('static')
in your views.
EDIT:
If you don't want to use any gem then I'll suggest checking out this question
What's the best way to create a static page in Rails?
Just create a view with the contents you'd have for the page, call it index.html.erb
, and leave the action method in the controller as a no-op.
Use page caching for bonus points.
Really static pages with Rails
There simple rake task (via GIST) to load all files from VIEW_PATH, wrap it with application layout and store it under same path in public. Work with Rails 4.
https://gist.github.com/potapuff/090b2da4a4156c1272430241cb70edc0
namespace :static do
desc 'Render all resources'
task :publicate => :environment do
resources(VIEW_PATH).each do |src, dest|
html= controller.render_to_string(file:src, layout:'application')
dirname = File.dirname(dest)
unless File.directory?(dirname)
FileUtils.mkdir_p(dirname)
end
File.write(dest, html)
end
end
def resources search_path
...
end
def controller
ApplicationController.new.tap do |controller|
...
end
end
end
Other possibility is using gem render_anywhere .
In Rails 5 we have new ability to use render outside controllers
https://medium.com/evil-martians/the-rails-5-post-9c76dbac8fc#1b36
Related Topics
Best Practices For Reusing Code Between Controllers in Ruby on Rails
Unresolved Specs During Gem::Specification.Reset:
How to Do Static Content in Rails
How to Get Filename Without Extension from File Path in Ruby
Convert Time from One Time Zone to Another in Rails
Using Send_File to Download a File from Amazon S3
Gem Install Permission Problem
How to Use Activerecord in a Ruby Script Outside Rails
How to Wrap Link_To Around Some HTML Ruby Code
How to Use Bundler Behind a Proxy
Rails4 Unknown Encoding Name - Cp720
What Is the Use of Gemfile in Rails
How to Use Global Variables or Constant Values in Ruby
Ruby Gsub Doesn't Escape Single-Quotes
How to Remove a Key from Hash and Get the Remaining Hash in Ruby/Rails