-
-
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? | |
# | |
# 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 |
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
render :controller => 'foo', :action => 'bar'
?