Rails routing: Giving default values for path help

2019-03-16 13:02发布

问题:

Is there some way to provide a default value to the url/path helpers?

I have an optional scope wrapping around all of my routes:

#config/routes.rb
Foo::Application.routes.draw do

  scope "(:current_brand)", :constraints => { :current_brand => /(foo)|(bar)/ } do
    # ... all other routes go here
  end

end

I want users to be able to access the site using these URLs:

/foo/some-place
/bar/some-place
/some-place

For convenience, I'm setting up a @current_brand in my ApplicationController:

# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_filter :set_brand

  def set_brand                                                                 
    if params.has_key?(:current_brand)                                          
      @current_brand = Brand.find_by_slug(params[:current_brand])               
    else                                                                        
      @current_brand = Brand.find_by_slug('blah')
    end
  end

 end

So far so good, but now I must modify all *_path and *_url calls to include the :current_brand parameter, even though it is optional. This is really ugly, IMO.

Is there some way I can make the path helpers automagically pick up on @current_brand?

Or perhaps a better way to define the scope in routes.rb?

回答1:

I think you will want to do something like this:

class ApplicationController < ActionController::Base

  def url_options
    { :current_brand => @current_brand }.merge(super)
  end

end

This method is called automatically every time url is constructed and it's result is merged into the parameters.

For more info on this, look at: default_url_options and rails 3



回答2:

In addition to CMW's answer, to get it to work with rspec, I added this hack in spec/support/default_url_options.rb

ActionDispatch::Routing::RouteSet.class_eval do
  undef_method :default_url_options
  def default_url_options(options={})
    { :current_brand => default_brand }
  end
end