50 votes

Un simple respond_with dans rails qui évite le 204 de PUT

Je veux PUT aux rails et éviter d'obtenir un 204 . J'utilise ce modèle :

class SomeController < ApplicationController
  respond_to :json

  def update
    # ...
    respond_with(some_object)
  end
end

Cependant, lorsque je fais un put pour mettre à jour, j'obtiens un 204 retour. Je réalise que c'est tout à fait valable, etc., mais je veux explicitement récupérer le contenu. Je peux le contourner dans une certaine mesure comme ceci :

def update
  respond_with(some_object) do |format|
    format.json{render json: some_object}
  end
end

mais cela semble un peu trop pratique pour les rails. Existe-t-il un moyen plus idiomatique d'éviter un fichier 204 et demander le renvoi de l'intégralité du contenu ? Nous sommes dans Rails 3.2.

En résumé, je veux des rails idiomatiques au maximum qui évitent une 204 .

31voto

jpfuentes2 Points 901

J'ai créé un répondeur personnalisé qui renvoie toujours ma ressource encodée en JSON, même en cas de PUT/POST.

J'ai mis ce fichier dans lib/responders/json_responder.rb . Votre /lib doit être chargé automatiquement.

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

Maintenant, modifiez explicitement le contrôleur qui requiert ce comportement, ou placez-le dans le contrôleur de l'application.

class ApplicationController < ActionController::Base

  protect_from_forgery

  responders :json

end

Vous devriez maintenant obtenir des ressources encodées en JSON en retour de PUT.

13voto

Ernesto Points 492

Comme alternative moins invasive, vous pouvez passer un json: à l'option respond_with invocation de la méthode dans votre contrôleur update action, comme ceci :

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

D'accord, il semble un peu difficile de répéter l'objet deux fois dans les arguments, mais vous obtiendrez ce que vous voulez, la représentation json de l'objet dans la réponse d'une requête PUT, et vous n'aurez pas besoin d'utiliser l'attribut render json: qui ne vous donnera pas les avantages des répondeurs.

Cependant, si vous avez beaucoup de contrôleurs dans cette situation, alors la personnalisation des répondeurs, comme jpfuentes2 l'a montré dans la réponse acceptée, est la solution. Mais pour un cas unique et rapide, cette alternative peut être plus facile.

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

11voto

Ce comportement semble intentionnel pour être en accord avec les spécifications HTTP, et "idéalement" vous devriez lancer une requête GET supplémentaire pour voir les résultats. Cependant, je suis d'accord pour dire que dans le monde réel, je préférerais qu'il renvoie le JSON.

La solution de @jpfuentes2 ci-dessus devrait faire l'affaire (elle est très similaire à la pull request ci-dessous), mais j'hésite à appliquer tout ce qui est Parcheando rails internals, car cela pourrait être une vraie douleur de mettre à jour entre les versions majeures, surtout si vous n'avez pas de tests pour cela (et avouons-le, les développeurs lésinent souvent sur les tests de contrôleur).

Références

9voto

patrick Points 1858

Juste pour clarifier, vous n'avez pas besoin de la gemme du répondant pour faire cela... Vous pouvez simplement le faire :

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

et ensuite soit (pour que toutes les actions de mise à jour soient affectées) :

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

ou dans votre action :

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

3voto

tybro0103 Points 13198

Qu'y a-t-il de mal à faire simplement :

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X