ruby-on-railsinterceptoractioncontroller

Is there a way to wrap the response of all controller methods in a json object in application_controller.rb?


I need to write some code in one place (base_controller.rb which inherits from application_controller.rb) that wraps all outgoing json responses from controllers in a json object before returning.

In my Rails (5.x.x) application, there are ~100 endpoints serving different types of data (json objects, arrays, array of arrays etc). Due to a recent requirement, I have to wrap them all in a parent object.

Previous state:

some_controller.rb

return_obj = { key: value }
render json: return_obj

Expected state:

some_controller.rb will return { key: value }, but this will be intercepted by base_controller.rb which in turn will return something like { payload: { key: value }, other_info: info }


Solution

  • Option-1: We have something similar in our setup, what we do is, that we have a method named render_response in our base_api_controller file. Which looks something like:

      def render_response(render_params)
        # controller_name, action_name will give you controller and action which rendered the response.
        # so you can decide weather to process anything or just render
    
        render_params[:json] = { payload: render_params[:json] }
        render render_params
      end
    

    And your controller action will convert to something like:

    return_obj = { key: value }
    render_response json: return_obj
    

    Personally(and obviously) I like first approach because it is explicit and looking at the controller code gives us the information that we are processing the response further.

    Option-2: If you don't like replacing render with render_response you can follow this guide to setup a rack middleware, which is also dead simple. but you will have to place checks of controllers if you don't want to do any updates for some specific controller actions. And also note that it will be automatic, so without anyone noticing(lets see someone completely new to your code) it will be changing the response. Which i personally don't like much.