Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Given a controller in need of refactoring into multiple controllers, how can I redirect to new controller actions based upon a feature flag?
# 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"}, []]
Owner
kneath commented Oct 18, 2012

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.

joeyw commented Oct 18, 2012
  # 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
joeyw commented Oct 19, 2012

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.

Owner
kneath commented Oct 19, 2012

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!

joeyw commented Oct 19, 2012
  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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment