method

controller

controller(params, default_controller=true)
public

If this is a default_controller (i.e. a controller specified by the user) we should raise an error in case it’s not found, because it usually means a user error. However, if the controller was retrieved through a dynamic segment, as in :controller(/:action), we should simply return nil and delegate the control back to Rack cascade. Besides, if this is not a default controller, it means we should respect the @scope[:module] parameter.

1Note

How to handle dynamic controller class evaluation based on params

stevo · Aug 30, 2012

Possible with following snippet of code (for instance if each branch has some different controller logic, but if the controller is not present, it should fallback to default controller).

Advantages are so we do not have to make blank inherited controllers and routes for them, to do it with plain inheritance.

class ActionDispatch::Routing::RouteSet::CustomDispatcher < ActionDispatch::Routing::RouteSet::Dispatcher # These are the controllers that we should attempt fallbacks on FALLBACK_CONTROLLERS = /customer\/branch\/(projects|events)$/

 def controller(params, default_controller=true)
   # This defines when we want to attempt fallbacks pattern
   super unless params[:branch_id] && params[:controller].try(:match, FALLBACK_CONTROLLERS)
   controller_param = params[:controller]

   # Having these supplied, we handle controller evaluation by our own method...
   controller_reference_with_fallbacks(params[:branch_id], controller_param)
 rescue NameError => e
   raise ActionController::RoutingError, e.message, e.backtrace if default_controller
 end

 private

 def controller_reference_with_fallbacks(branch_id, controller_param)
   # This is how fallbacks are evaluated       
   controller_name = "#{controller_param.sub('/branch', "/branch/#{branch_id}").camelize}Controller"

   controller = ActiveSupport::Dependencies.reference(controller_name)

   begin
     controller.get(controller_name)
   rescue NameError => e  # If there is no specific class for given branch, fallback to original class
     controller_reference(controller_param)
   end
 end

end

ActionDispatch::Routing::Mapper::Mapping.class_eval do private

 # We do overwrite dispatcher class, that is used to evaluate controller classes from params
 def app
   ActionDispatch::Routing::Mapper::Constraints.new(
       to.respond_to?(:call) ? to : ::ActionDispatch::Routing::RouteSet::CustomDispatcher.new(:defaults => defaults),
       blocks,
       @set.request_class
   )
 end

end