3

Is it possible to create an after_filter method in the Rails ApplicationController that runs on every action and renders to JSON? I'm scaffolding out an API, and I'd like to render output to JSON for every action in the controller.

clients_controller.rb

def index
  @response = Client.all
end

application_controller.rb

...
after_action :render_json
def render_json
  render json: @response
end

The after_action is never executed, and the code aborts with:

Template is missing. Missing template clients/index, ...

If the render json: @response is moved into the controller action, it works correctly.

Is there a filter that will allow me to DRY up the controllers and move the render calls to the base controller?

Feckmore
  • 3,472
  • 5
  • 39
  • 47

1 Answers1

5

You can't render after_action/ after_filter. The callback after_action is for doing stuff after rendering. So rendering in after_action is too late.
But your exception is just because you miss the JSON template. I recommend using RABL (which offers a lot of flexibility to your JSON responses and there is also a Railscast about it). Then your controller could look like:

class ClientsController < ApplicationController
  def index
    @clients = Client.all
  end
  def show
    @client = Client.find params[:id]
  end
end

And don't forget to create your rabl templates.
e.g. clients/index.rabl:

collection @clients, :object_root => false

attributes :id
node(:fancy_client_name) { |attribute| attribute.client_method_generating_a_fancy_name }

But in the case you still want to be more declarative you can take advantage of the ActionController::MimeResponds.respond_to like:

class ClientsController < ApplicationController
  respond_to :json, :html
  def index
    @clients = Client.all
    respond_with(@clients)
  end
  def show
    @client = Client.find params[:id]
    respond_with(@client)
  end
end

Btw. beware if you put code in an after_action, this will delay the whole request.

Christian Rolle
  • 1,544
  • 10
  • 13