Comment remplacer to_json dans Rails?


Mettre à jour:

Cette question n’a pas été correctement explorée. Le véritable problème réside dans le render :json .

Le premier code collé dans la question d’origine donnera le résultat attendu. Cependant, il y a toujours une réserve. Voir cet exemple:

render :json => current_user

n’est pas la même que

render :json => current_user.to_json

C’est-à-dire render :json n’appellera pas automatiquement la méthode to_json associée à l’object User. En fait , si to_json est remplacé sur le modèle User , render :json => @user générera l’ ArgumentError décrit ci-dessous.

résumé

 # works if User#to_json is not overridden render :json => current_user # If User#to_json is overridden, User requires explicit call render :json => current_user.to_json 

Tout cela me semble idiot. Cela semble me dire que le render n’appelle pas réellement le Model#to_json lorsque le type :json est spécifié. Quelqu’un peut-il expliquer ce qui se passe vraiment ici?

Tous les génies qui peuvent m’aider avec ceci peuvent probablement répondre à mon autre question: comment créer une réponse JSON en combinant @ foo.to_json (options) et @ bars.to_json (options) dans Rails


Question originale:

J’ai vu d’autres exemples sur SO, mais aucun ne fait ce que je cherche.

J’essaie:

 class User  :username, :methods => [:foo, :bar]) end end 

J’obtiens ArgumentError: wrong number of arguments (1 for 0) dans

 /usr/lib/ruby/gems/1.9.1/gems/activesupport-2.3.5/lib/active_support/json/encoders/object.rb:4:in `to_json 

Des idées?

Vous obtenez ArgumentError: wrong number of arguments (1 for 0) car to_json doit être remplacé par un paramètre, les options hash.

 def to_json(options) ... end 

Explication plus longue de to_json , as_json et rendu:

Dans ActiveSupport 2.3.3, as_json été ajouté pour résoudre des problèmes tels que celui que vous avez rencontré. La création de json devrait être distincte du rendu de json.

Désormais, chaque fois que to_json est appelé sur un object, as_json est as_json pour créer la structure de données, puis ce hachage est codé en tant que chaîne JSON à l’aide d’ ActiveSupport::json.encode . Cela se produit pour tous les types: object, numérique, date, chaîne, etc. (voir le code ActiveSupport).

Les objects ActiveRecord se comportent de la même manière. Il existe une implémentation as_json par défaut qui crée un hachage qui inclut tous les atsortingbuts du modèle. Vous devez remplacer as_json dans votre modèle pour créer la structure JSON souhaitée . as_json , tout comme l’ancien to_json , prend une option de hachage où vous pouvez spécifier des atsortingbuts et des méthodes à inclure de manière déclarative.

 def as_json(options) # this example ignores the user's options super(:only => [:email, :handle]) end 

Dans votre contrôleur, render :json => o peut accepter une chaîne ou un object. Si c’est une chaîne, elle est transmise en tant que corps de réponse, si c’est un object, to_json est appelé, ce qui déclenche as_json comme expliqué ci-dessus.

Donc, tant que vos modèles sont correctement représentés avec as_json overrides (ou non), le code de votre contrôleur pour afficher un modèle doit ressembler à ceci:

 format.json { render :json => @user } 

La morale de l’histoire est la suivante: évitez d’appeler directement to_json , laissez le faire faire cela pour vous. Si vous devez modifier la sortie JSON, appelez as_json .

 format.json { render :json => @user.as_json(:only => [:username], :methods => [:avatar]) } 

Si vous rencontrez des problèmes avec Rails 3, remplacez serializable_hash au lieu de as_json . Cela vous permettra également d’obtenir votre formatage XML gratuit 🙂

Cela m’a pris pour toujours à comprendre. J’espère que ça aide quelqu’un.

Pour les personnes qui ne veulent pas ignorer les options des utilisateurs mais qui ajoutent également leurs options:

 def as_json(options) # this example DOES NOT ignore the user's options super({:only => [:email, :handle]}.merge(options)) end 

J’espère que cela aide quelqu’un 🙂

Ne remplacez pas to_json, mais as_json. Et depuis as_json appelez ce que vous voulez:

Essaye ça:

 def as_json { :username => username, :foo => foo, :bar => bar } end