[ACCEPTED]-What's the correct way to run one controller action from another controller action without an HTTP redirect?-ruby-on-rails
Instead of calling code across actions, extract 2 the code to lib/ or something, and call 1 that code from both controllers.
# lib/foo.rb module Foo def self.bar # ... end end # posts_controller def index Foo.bar end # things_controller def index Foo.bar end
Create an instance of the controller class:
@my_other_controller = MyOtherController.new
Then 3 call methods on it:
I prefer the module idea, but 2 this should do the trick.
You can also pass 1 parameters as a whole from another controller:
@my_other_controller.params = params
I suspect you want option 3, but lets go 22 through the some alternatives first
Option 1 - Push 21 the controller selection logic into a helper 20 that inserts the right link into your view. Benifits 19 - controllers remain clean, Cons - if decision 18 logic depending on submitted values this 17 approach won't work. If URL is being called 16 by external websites then this won't work.
Option 2 - Push 15 the logic back into your model. Pro's - keeps 14 controller clean. Cons - doesn't work well 13 if you've got lots of sesson, params or 12 render / redirect_to interaction.
Option 3 - Stay 11 within the same controller. I suspect you 10 are trying to replace some existing functionality 9 with some new functionality, but only in 8 some cases. Pro's - Simple and have access 7 to everything you need. Cons - only works 6 if it makes sense to use the same controller 5 i.e. you're working with the same entity 4 such as user, place or company.
Lets look 3 an an example for option 3. My links controller 2 has totally diferent behavour for admins 1 than other users ...
class LinksController < ApplicationController #... def new #Check params and db values to make a choice here admin? ? new_admin : new_user end #... private def new_admin #All of the good stuff - can use params, flash, etc render :action => 'new_admin' end def new_user #All of the good stuff - can use params, flash, etc render :action => 'new_user' end end
If two controllers are trying to do the 10 same thing, there's a very good chance this 9 should be in a model. Take a good look 8 at your design and -- I'm sorry I don't 7 know your experience level with MVC -- read 6 up on thin controller techniques:
http://weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-model http://www.robbyonrails.com/articles/2007/06/19/put-your-controllers-on-a-diet-already http://andrzejonsoftware.blogspot.com/2008/07/mvc-how-to-write-controllers.html
If the 5 problem is that you need the other controller 4 to do the render, then maybe the route should 3 have pointed there to begin with, and still 2 the skinny controller technique should save 1 the day.
If extracting the common code between controllers 25 into a module doesn't work for you, I would 24 use Rack middleware. I haven't seen code 23 that uses
ActiveRecord within middleware but I don't 22 know of any reason why it shouldn't be possible 21 since people have used
Redis and the like.
Otherwise 20 I think your only option would be to restart 19 processing of the request with something 18 like (untested, pseudo example):
env['REQUEST_URI'] = new_controller_uri_with_your_params call(env)
This is 17 similar to how integration tests are implemented. But 16 I don't know if everything from
call until you 15 hit a controller is idempotent and safe 14 to rerun like this. You could trace through 13 the source and see. But even if it's ok 12 now, it might break in any future version 11 of rails or rack.
Using middleware would 10 avoid this by letting you intercept the 9 request before it's been run. You should 8 still be able to share code with your rails 7 application by extracting it out into common 6 modules included in both places.
Honestly 5 I think just doing the simple thing of factoring 4 the common controller code is likely cleaner, but 3 it's hard to know without the details of 2 your situation so I thought I'd go ahead 1 and suggest this.
More Related questions