Rails: call another controller action from a controller
Ruby on-RailsRuby on-Rails Problem Overview
I need to call the create action in controller A, from controller B.
The reason is that I need to redirect differently when I'm calling from controller B.
Can it be done in Rails?
Ruby on-Rails Solutions
Solution 1 - Ruby on-Rails
To use one controller from another, do this:
def action_that_calls_one_from_another_controller
controller_you_want = ControllerYouWant.new
controller_you_want.request = request
controller_you_want.response = response
controller_you_want.action_you_want
end
Solution 2 - Ruby on-Rails
You can use a redirect to that action :
redirect_to your_controller_action_url
More on : Rails Guide
To just render the new action :
redirect_to your_controller_action_url and return
Solution 3 - Ruby on-Rails
The logic you present is not MVC, then not Rails, compatible.
-
A controller renders a view or redirect
-
A method executes code
From these considerations, I advise you to create methods in your controller and call them from your action.
Example:
def index
get_variable
end
private
def get_variable
@var = Var.all
end
That said you can do exactly the same through different controllers and summon a method from controller A while you are in controller B.
Vocabulary is extremely important that's why I insist much.
Solution 4 - Ruby on-Rails
You can use url_for
to get the URL for a controller and action and then use redirect_to
to go to that URL.
redirect_to url_for(:controller => :controller_name, :action => :action_name)
Solution 5 - Ruby on-Rails
This is bad practice to call another controller action.
You should
- duplicate this action in your controller B, or
- wrap it as a model method, that will be shared to all controllers, or
- you can extend this action in controller A.
My opinion:
-
First approach is not DRY but it is still better than calling for another action.
-
Second approach is good and flexible.
-
Third approach is what I used to do often. So I'll show little example.
def create @my_obj = MyModel.new(params[:my_model]) if @my_obj.save redirect_to params[:redirect_to] || some_default_path end end
So you can send to this action redirect_to
param, which can be any path you want.
Solution 6 - Ruby on-Rails
Perhaps the logic could be extracted into a helper? helpers are available to all classes and don't transfer control. You could check within it, perhaps for controller name, to see how it was called.
Solution 7 - Ruby on-Rails
[Composition][1] to the rescue!
Given the reason, rather than invoking actions across controllers one should design controllers to seperate shared and custom parts of the code. This will help to avoid both - code duplication and breaking MVC pattern.
Although that can be done in a number of ways, using concerns ([composition][1]) is a good practice.
# controllers/a_controller.rb
class AController < ApplicationController
include Createable
private def redirect_url
'one/url'
end
end
# controllers/b_controller.rb
class BController < ApplicationController
include Createable
private def redirect_url
'another/url'
end
end
# controllers/concerns/createable.rb
module Createable
def create
do_usefull_things
redirect_to redirect_url
end
end
Hope that helps. [1]: https://en.wikipedia.org/wiki/Object_composition
Solution 8 - Ruby on-Rails
You can call another action inside a action as follows:
redirect_to action: 'action_name'
class MyController < ApplicationController
def action1
redirect_to action: 'action2'
end
def action2
end
end
Solution 9 - Ruby on-Rails
Separate these functions from controllers and put them into model file. Then include the model file in your controller.