How to do static content in Rails?
Asked Answered
M

8

75

Looking at different options:

One is to just put the static pages in the public/ folder, but I do want the header from layout/application to be consistent.

I tried this, but I got an error:

# in routes.rb:
map.connect '*path', :controller => 'content', :action => 'show'

# in content_controller.rb:
def show
  render :action => params[:path].join('/')
end

All I want is an easy way to put together things like my faq, contact, tos, privacy, and other non-application type pages somewhere easy by just creating an .rhtml. who has done this?

Maganmagana answered 18/7, 2009 at 3:23 Comment(0)
E
31

thoughtbot has a plugin called high_voltage for displaying static content: https://github.com/thoughtbot/high_voltage

Evacuate answered 6/11, 2009 at 16:46 Comment(0)
Y
179

For Rails6, Rails5 and Rails4 you can do the following:

Put the line below at the end of your routes.rb

  get ':action' => 'static#:action'

Then requests to root/welcome, will render the /app/views/static/welcome.html.erb.

Don't forget to create a 'static' controller, even though you don't have to put anything in there.

Limitation: If somebody tries to access a page that does not exist, it will throw an application error. See this solution below that can handle 404s

For Rails3 you have to use 'match' instead of 'get'

  match ':action' => 'static#:action'
Yours answered 11/2, 2011 at 7:56 Comment(11)
+1 Awesome, just what I needed. This should get more votes up as it's for the latest Rails.Cervelat
If anyone else is wondering, the ":action" here is magic; it won't work if you call it ":id" or ":title" or whatever.Supramolecular
In Rails4, I get an alert in development mode saying to replace "match" with "get".Germane
@Germane why don't you check how it works in rails4 and post it as a new answer, don't have the time right now to update my answer.Yours
@RolandStuder Sorry I wasn't clear - all you have to do is replace "match" with "get" and it works perfectly. :)Germane
@Germane Tested it now, works nicely with get, I updated my answer to reflect that. Thanks a lot for your input!Yours
You can also also use ':to', generate named routes with ':as', and add constraints with regular expressions: "get ':action', to: 'static#:action', as: static, action: /(eat|drink|sleep)/".Canopy
How to avoid exceptions since this is a catch-all? Ideally you want to give a 404, not trigger an exception. I was trying to find how this is documented, it is not triggering a missing method, it just looks for the view on disk.Firman
See https://mcmap.net/q/266276/-how-to-do-static-content-in-rails for a extended, but just as convenient solution that handles 404sYours
How would I handle routing in this case? Can I use the rails lin_to helper with this method?Egg
@Egg No, as this works as a wild card, there are no link_to helpers. You point to the raw paths like /helloYours
E
31

thoughtbot has a plugin called high_voltage for displaying static content: https://github.com/thoughtbot/high_voltage

Evacuate answered 6/11, 2009 at 16:46 Comment(0)
M
22

depends on the url structure, if you want the paths to come off of / (e.g. /about_us), then:

map.connect ':action', :controller => "static"

This should go at the very end of your routes file, Throw your .html.erb files into app/views/static and you are done.

e.g: throwing in about_us.html.erb, will give you a page at /about_us.

The item that you have in your question is great for a catch all route where you can analyze the array given to you at params[:path]. A bit more information on that at http://railscasts.com/episodes/46-catch-all-route

Misunderstanding answered 19/7, 2009 at 11:9 Comment(0)
M
13

Rendering an action doesn't make sense. You'll want to render a template (or a file) with a layout.

# Path relative to app/views with controller's layout
render :template => params[:path]

# ... OR

# Absolute path. You need to be explicit about rendering with a layout
render :file => params[:path], :layout => true

You could serve a variety of different templates from a single action with page caching.

# app/controllers/static_controller.rb
class StaticController < ApplicationController
  layout 'static'

  caches_page :show

  def show
    valid = %w(static1 static2 static3)
    if valid.include?(params[:path])
      render :template => File.join('static', params[:path])
    else
      render :file   => File.join(Rails.root, 'public', '404.html'), 
             :status => 404
    end
  end
end

Lastly, we'll need to define a route.

# config/routes.rb
map.connect 'static/:path', :controller => 'static', :action => 'show'

Try accessing these static pages. If the path doesn't include a valid template, we'll render the 404 file and return a 404 status.

  • http://localhost:3000/static/static1
  • http://localhost:3000/static/static3
  • http://localhost:3000/static/static2

If you take a look in app/public you'll notice a static/ directory with static1.html, static2.html and static3.html. After accessing the page for the first time, any subsequent requests will be entirely static thanks to page caching.

Madcap answered 18/7, 2009 at 4:26 Comment(0)
M
3

I used the idea of a generalized controller from the answers given, but I wanted to catch 404s, so I put an action in it to handle either case:

# app/controllers/static_controller.rb
class StaticController < ApplicationController
    def static_or_404
        render params[:static]
    rescue ActionView::MissingTemplate
        render :not_found
    end
end

and then at the very bottom in my routing:

# config/routes.rb
get '*static', to: 'static#static_or_404'

It serves the view from app/views/static of the same name as the path, and if there isn't such a view, it serves app/views/static/not_found.html.erb. One could also replace render :not_found with redirect_to root_path or anything else one wanted to have happen.

Merrifield answered 24/1, 2020 at 20:7 Comment(2)
Awesome stuff! I just came back to my answer and wanted to write up how to handle 404s then I saw you already did that, and now I link to your solution instead. In a way it would still be good to update my answer for visibility. Or maybe you want to make an edit to my answer, so you get some attribution. Much deserved upvote. I hope that the best answer, will not stay with the least votes for too long.Yours
This is great. I was able to rip out high voltage and replace it with 8 lines of code. Thanks very much, this is super helpful.Egg
P
2

Considering if u have 1 Home Controller with couple method like show, aboutus, privacy :

class HomesController < ApplicationController
  def show
  end
  def privacy
  end
  def aboutus
  end
end

And map the show method to your root, and map the other to some named routes like

map.root      :controller => "homes", :action => "show"
map.aboutus "/aboutus", :controller => "homes", :action => "aboutus"
map.privacy "/privacy", :controller => "homes", :action => "privacy"

And with view for each

app/views/homes/aboutus.html.erb --> you get http://localhost:3000/aboutus
app/views/homes/show.html.erb --> you get http://localhost:3000 (root)
app/views/homes/privacy.html.erb --> you get http://localhost:3000/privacy

All using the same layout at app/views/layout/application.html.erb

Pyriform answered 18/7, 2009 at 10:28 Comment(0)
U
2

Lindsaar solution is one of the best I ever seen. He build a caching static pages that expired when git revision changed.

<%= cache "site-page-#{@page_name}-#{App.git_revision}" do %>
  <%= render :partial => @page_name %>
<% end %>
Underworld answered 4/11, 2012 at 9:40 Comment(0)
S
1

Create a PagesController for your static pages (e.g contact) and insert

def contact_page
end

in config/routes.rb insert

get 'contact' => 'pages#contact_page'

which will display the content from views/pages/contact_page.html.erb

Stealer answered 27/4, 2015 at 16:0 Comment(1)
Why the downvote? I appreciate my answer relates to Rails 4, but will answer someones question nonetheless.Stealer

© 2022 - 2024 — McMap. All rights reserved.