method

controller

Importance_2
v3.0.0 - Show latest stable - 1 note - Class: ActionDispatch::Routing::RouteSet::Dispatcher
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 an 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.

Show source
Register or log in to add new notes.
August 30, 2012
0 thanks

How to handle dynamic controller class evaluation based on params

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