Call Another Controller Action In Rails
2020-11-16
RailsSometimes we want to reuse a controller's action in another controller for some reasons. We know redirect is an answer of that, however, there is no way to touch the response when using redirect, and it might be necessary to modify the response, such as transforming response body to another format.
To solve this, use XxxController.dispatch to call an another controller's action.
class ItemsController < ActionController::Base
include Rails.application.routes.url_helpers
def show
request.params[:item_id] = request.params[:id]
res = AnotherController.dispatch(:get, request, response)
render json: { msg: "OK", body: JSON.parse(res[2].body) }, status: 200
end
end
class AnotherController < ActionController::Base
include Rails.application.routes.url_helpers
def get
item = {
"1" => "hello",
"2" => "world",
}[params[:item_id]]
render json: { item: item }, status: 200
end
end
You can get AnotherController#get results via ItemsController#show like
$ curl "localhost:3000/items/1" | jq .
{
"body": {
"item": "hello"
},
"msg": "OK"
}
Furthermore, if you want to get instance variables that are assigned in the dispatched controller, using #dispatch instead of .dispatch will be a way to do it.
+ ac = AnotherController.new
- res = AnotherController.dispatch(:get, request, response)
+ res = ac.dispatch(:get, request, response)
+ instance_var = ac.instance_variable_get(:@whatever_you_want)
Reproducible code is available in gist.