Skip to content

Instantly share code, notes, and snippets.

@kneath
Created October 18, 2012 21:26
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kneath/3914835 to your computer and use it in GitHub Desktop.
Save kneath/3914835 to your computer and use it in GitHub Desktop.
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
@bratsche
Copy link

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

@halorgium
Copy link

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

Then return a response which has

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

@kneath
Copy link
Author

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
Copy link

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
Copy link

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.

@kneath
Copy link
Author

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
Copy link

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