public
Created

Given a controller in need of refactoring into multiple controllers, how can I redirect to new controller actions based upon a feature flag?

  • Download Gist
controllers.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
# Given a controller in need of refactoring into multiple controllers, how
# can I redirect to new controller actions based upon a feature flag?
#
# The current code "works" but doesn't exercise the controller action.
#
# Rails 2.3 or 3.0 methods accepted
 
class BetterController
def overview
# .. a small amount of auth/permissions code
end
end
 
class PoorlyNamedController
def show
if feature_flag?
render :template => 'better/overview', :layout => 'new_layout'
return
end
 
# ... tons of code here in a horrible method that needs to be split
# into multiple methods across many controllers
end
end

render :controller => 'foo', :action => 'bar' ?

request.env["PATH_INFO"] = "/better/overview"

Then return a response which has

[404, {"X-Cascade" => "pass"}, []]

So what I have right now gets very close, unfortunately this app is in the middle of being both Rails 2.GitHub and Rails 3.GitHub, so it's hard to nail down what's going on.

  # This is NOT to be meant for constant use, but is useful when you want
  # to refactor a controller method into many controllers or into an action
  # in another controller and want to do it staff-only for a while.
  #
  # controller - The controller Class you wish to render.
  # action     - The controller action Symbol you wish to render.
  def render_in_controller(controller, action)
    c = controller.new
    c.request = @_request
    c.response = @_response
    c.params = params
    c.send(action)
    c.response.body
  end

This works, except the response body is always nil. Calling render :template => 'better/overview' after calling render_in_controller works exactly as expected. I'd just love if it let the controller action figure out what to render.

  # This is NOT to be meant for constant use, but is useful when you want
  # to refactor a controller method into many controllers or into an action
  # in another controller and want to do it staff-only for a while.
  #
  # controller - The controller Class you wish to render.
  # action     - The controller action Symbol you wish to render.
  def render_in_controller(controller, action)
    c = controller.new
    c.request = @_request
    c.response = @_response
    c.params = params
    c.process(action)
    c.response.body
  end
  def index
    render :inline => render_in_controller(TestersController, 'index')
    return
  end

This works with 2.3: http://www.railsonwave.com/2008/10/25/how-to-call-a-controller-s-action-from-a-different-controller

I had to change Inflector to ActiveSupport::Inflector for it to work for me though.

Man that's reallly close. Still it's trying to call the same action name (not the action name I'm sending it). I added the action name into the .process call in request, response, options[:action] but still wants the same name.

Thanks a ton though, this is getting very close!

  def internal_redirect_to(options={})
    params.merge!(options)
    request.env['action_controller.request.path_parameters']['controller'] = params[:controller]
    request.env['action_controller.request.path_parameters']['action'] = params[:action]
    (c = ActionController.const_get(ActiveSupport::Inflector.classify("#{params[:controller]}_controller")).new).process(request,response)
    c.instance_variables.each{|v| self.instance_variable_set(v,c.instance_variable_get(v))} 
  end

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.