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.
https://gist.github.com/petitviolet/1f7965e2c3624f475282d71df6b36c58