Best practices for static pages in rails app

2019-07-01 10:42发布

问题:

I am developing a app in ruby on rails for a local business. The pages are 'static', but changeable through a backend CMS I am building for them. Is there a best practice to creating a controller for static pages? Right now I have a sites 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 would I be better off creating member routes for the site controller like this without the crud, because a 'Site' will not need to have the 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

回答1:

If the static pages list are not going to increase, then you can keep the list, but if you want a dynamic list like site/any_new_url , save the routes as

get 'site/:cms_page' => 'cms#show' # all requests matching site/any_page will go CmsController, show method

This will help reduce keep the routes from bloating, but the downside is you do not know what all routes are the valid ones. Your sample code can be

def show
  @page_data = Page.find_by_page(:params[:cms_page])
end

show.html.erb

<%= @page_data.html_safe %>


回答2:

Dunno yet if I consider this a best practice or an abomination but here is what I came up with when tackling the same problem.

My reasoning is that the site was providing some specified functionality (which doesn't really matter for this discussion) + a bunch of information about the organisation itself (about us, contact, FAQ, homepage blurb, whatever). Since all that data was really related to the organisation, an Organisation model seemed reasonable with each of those things as attributes. Here is 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 routes based on the columns. This is in my routes.rb:

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 gets a little weird and I am not thrilled with the code here but here it is anyway. I need to make sure the attribute is set and available to the views so I can do the right thing there so I set it in the application controller:

class ApplicationController < ActionController::Base
  protect_from_forgery
  before_filter :set_attribute

  def set_attribute
    @attribute = action_name.parameterize
  end

end

For the organisation controller I just set the @organisation variable to be the first and only row in the database in the before_filter and then let Rails do its usual magic of calling the method, failing, and rendering a view of the same name. The edit action just uses one view file to edit all the 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 that is where I ended up. Like you I hit up SO to tap into the seething mass of genius here but ended up with disappointing results. If there is something better out there I am still hoping to find it.

What I like about what I did is that routes are automatically generated based on the structure of the organisation table.

What I don't like about what I did is that routes automatically generated based on the structure of the organisation table.

I know I will pay for that design decision when I have to deal with i18n routing and there are probably a thousand other reasons that this is a bad idea that I have yet to discover but for the moment I have a happy client.

In the end this is not a suggestion that you should do this, but I am hoping to give you more than I got so you can advance your thinking on this and hopefully end up a little closer to that best practice.



回答3:

If you are going to construct a CMS, which likely connects to a database, and allow your customer to change the text on the pages of their site, I would not recommend using static pages. In Rails terms, a static page would refer to creating html files in your /views/pages directory. If you go this route, then you're walking outside of the way that Rails was designed.

I believe that what you want to do is create tables in the database that correspond to and store the data for your posts, etc. You can pull information into the controller from the model that it corresponds to and then user a view to display the data. You can create a layout for these pages and then create controllers for each of the pages that you add.

As far as routes, I would recommend using the following:

map.resource :controller_name

you then would add the code that displays the information from the CMS in the corresponding show controller action and view for each page.