Simple respond_with in rails that avoids 204 from PUT

Solution 1:

I made a custom responder which always returns my JSON encoded resource even on PUT/POST.

I put this file in lib/responders/json_responder.rb. Your /lib dir should be autoloaded.

module Responders::JsonResponder
  protected

  # simply render the resource even on POST instead of redirecting for ajax
  def api_behavior(error)
    if post?
      display resource, :status => :created
    # render resource instead of 204 no content
    elsif put?
      display resource, :status => :ok
    else
      super
    end
  end
end

Now, explicitly modify the controller which requires this behavior, or place it in the application controller.

class ApplicationController < ActionController::Base

  protect_from_forgery

  responders :json

end

You should now get JSON encoded resources back on PUT.

Solution 2:

As a less invasive alternative, you can pass a json: option to the respond_with method invocation inside your controller update action, like this:

def update
  # ...
  respond_with some_object, json: some_object
end

Granted it seems a bit unDRY having to repeat the object twice in the arguments, but it'll give you what you want, the json representation of the object in the response of a PUT request, and you don't need to use the render json: way, which won't give you the benefits of responders.

However, if you have a lot of controllers with this situation, then customizing the responders, as jpfuentes2 showed in the accepted anwser, is the way to go. But for a quick single case, this alternative may be easier.

Source: https://github.com/plataformatec/responders/pull/115#issuecomment-72517532

Solution 3:

This behavior seems intentional to fall in line with the HTTP spec, and "ideally" you should be firing off an additional GET request to see the results. However, I agree in the real world I'd rather have it return the JSON.

@jpfuentes2's solution above should do the trick (it's very similar to the pull request below), but I'm hesitant to apply anything that's patching rails internals, as it could be a real pain to upgrade between major versions, especially if you don't have tests for it (and let's face it, developers often skimp on controller tests).

References

  • https://github.com/rails/rails/issues/9862
  • https://github.com/rails/rails/pull/9887

Solution 4:

Just to clarify, you do not need the responders gem to do this... You can just do:

config/initializers/responder_with_put_content.rb

class ResponderWithPutContent < ActionController::Responder
  def api_behavior(*args, &block)
    if put?
      display resource, :status => :ok
    else
      super
    end
  end
end

and then either (for all updates actions to be affected):

class ApplicationController < ActionController::Base
  def self.responder
    ResponderWithPutContent
  end
end

or in your action:

def update
  foo = Foo.find(params[:id])
  foo.update_attributes(params[:foo])
  respond_with foo, responder: ResponderWithPutContent
end

Solution 5:

What's wrong with simply doing:

def update
  some_object = SomeObject.update()
  render json: some_object
end