Best practices for static pages in a rails app
I am developing an app in ruby on rails for a local business. The pages are "static" but are modified by the backend CMS I create for them. Is there a best practice for creating a controller for static pages? Right now I have a site controller with all static routes like this.
routes.rb
get "site/home"
get "site/about_us"
get "site/faq"
get "site/discounts"
get "site/services"
get "site/contact_us"
get "site/admin"
get "site/posts"
or I'd be better off creating member routes for the site controller like this without the crud, because the "site" doesn't need CRUD.
resources :sites, :except => [:index, :new, :create, :update, :destroy]
member do
get :home
get :about_us
get :faq
get :discounts
get :services
get :contact_us
get :admin
get :posts
end
Or is there a best practice / better way? Any answers would be appreciated. Thanks to
source to share
If the list of static pages won't grow, you can keep the list, but if you need a dynamic list like site / any_new_url, keep the routes as
get 'site/:cms_page' => 'cms#show' # all requests matching site/any_page will go CmsController, show method
This will help reduce the retention of routes from bloating, but the downside is that you don't know that all routes are valid. Your example code could be
def show
@page_data = Page.find_by_page(:params[:cms_page])
end
show.html.erb
<%= @page_data.html_safe %>
source to share
I don't know if I consider this to be best practice or an abomination, but here is what I came up with while solving the same problem.
My reasoning is that the site provided some functionality (which doesn't really matter to this discussion) + a bunch of information about the organization itself (about us, contacts, FAQ, home page, whatever). Since all of this data was really related to the organization, the Organization model seemed reasonable with each of these things as attributes. Here's the model:
class Organisation < ActiveRecord::Base
...validations stuff...
def self.attrs_regex
Regexp.new(self.attrs.join("|"))
end
def self.attrs
self.column_names.reject{|name| name =~ /id|created_at|updated_at/}
end
end
Then I use the attrs class method to generate the column-based routes. This is in my .rb routes:
Organisation.attrs.each do |attr|
get "#{attr}" => "organisation##{attr}", :as => attr.to_sym
get "#{attr}/edit" => "organisation#edit", :as => "#{attr}_edit".to_sym, :defaults => { :attribute => attr }
post "#{attr}" => "organisation#update", :as => :organisation_update, :defaults => { :attribute => attr}, :constraints => Organisation.attrs_regex
end
The controller is a little weird and I'm not crazy about the code here, but it doesn't matter here. I need to make sure the attribute is set and available for views, so I can get it right, so I set it in my app controller:
class ApplicationController < ActionController::Base
protect_from_forgery
before_filter :set_attribute
def set_attribute
@attribute = action_name.parameterize
end
end
For the organization controller, I just set the @organisation variable as the first and only line in the database in the before_filter, and then lets Rails do the usual magic of calling a method, failing, and rendering the same name.The edit action just uses one view file to edit all different attributes:
class OrganisationController < ApplicationController
before_filter :set_organisation
def edit
authorize! :edit, @organisation
@attribute = params[:attribute].parameterize
end
def update
authorize! :update, @organisation
@attribute = params[:attribute]
respond_to do |format|
if @organisation.update_attributes(params[:organisation])
format.html do
redirect_to "/#{@attribute}", notice: t('successful_update')
end
format.json { head :ok }
else
format.html { render action: "edit" }
end
end
end
private
def set_organisation
@organisation = Organisation.first
end
end
So this is where I ended up. Like you, I ended up on SO to bring in a ton of genius here, but ended up with disappointing results . If there is something better, I still hope to find it.
What I like about what I have done is that the routes are automatically generated based on the organization table structure.
What I don't like about what I have done is that the routes are automatically generated based on the organization table structure.
I know I will pay for this design decision when I have to tinker with i18n routing, and there are probably a thousand other reasons that this is a bad idea that I haven't discovered yet, but I have a happy client at this point.
At the end of the day, that doesn't mean you should be doing this, but I hope to give you more than I do so that you can advance your thinking on this and hopefully end up a little closer to this best practice.
source to share
If you are going to create a CMS that probably connects to a database and allows your client to change the text on the pages of their site, then I would not recommend using static pages. In Rails terms, a static page will link to create html files in the / views / pages directory. If you go this route, you are going beyond how Rails was designed.
I believe you want to create tables in the database that match and store data for your posts, etc. You can pull information into the controller from the model it matches and then the user sees the data display. You can create a layout for these pages and then create controllers for each page you add.
As far as routes are concerned, I would recommend using the following:
map.resource :controller_name
you will then add code that displays the information from the CMS in the appropriate show and view manager action for each page.
source to share