Comment construire une réponse JSON composé de plusieurs modèles dans les Rails

Tout d'abord, le résultat souhaité

J'ai User et Item modèles. J'aimerais construire une réponse JSON qui ressemble à ceci:

{
  "user":
    {"username":"Bob!","foo":"whatever","bar":"hello!"},

  "items": [
    {"id":1, "name":"one", "zim":"planet", "gir":"earth"},
    {"id":2, "name":"two", "zim":"planet", "gir":"mars"}
  ]
}

Cependant, mon User et Item modèle ont plus d'attributs que ceux. J'ai trouvé un moyen d'obtenir que cela fonctionne, mais méfiez-vous, c'est pas joli... s'il vous Plaît aider...

Mise à jour

La section suivante contient la question d'origine. La dernière section présente la nouvelle solution.


Mon hacks

home_controller.rb

class HomeController < ApplicationController

  def observe
    respond_to do |format|
      format.js { render :json => Observation.new(current_user, @items).to_json }
    end
  end

end

observation.rb

# NOTE: this is not a subclass of ActiveRecord::Base
# this class just serves as a container to aggregate all "observable" objects
class Observation
  attr_accessor :user, :items

  def initialize(user, items)
    self.user = user
    self.items = items
  end

  # The JSON needs to be decoded before it's sent to the `to_json` method in the home_controller otherwise the JSON will be escaped...
  # What a mess!
  def to_json
    {
      :user => ActiveSupport::JSON.decode(user.to_json(:only => :username, :methods => [:foo, :bar])),
      :items => ActiveSupport::JSON.decode(auctions.to_json(:only => [:id, :name], :methods => [:zim, :gir]))
    }
  end
end

Regarde Ma! Pas plus de hacks!

Remplacer as_json au lieu

La ActiveRecord::Sérialisation#as_json docs sont assez rares. Voici la bref:

as_json(options = nil) 
  [show source]

Pour plus d'informations sur to_json vs as_json, voir la accepté de répondre pour Primordial to_json dans les Rails 2.3.5

Le code sans hacks

de l'utilisateur.rb

class User < ActiveRecord::Base

  def as_json(options)
    options = { :only => [:username], :methods => [:foo, :bar] }.merge(options)
    super(options)
  end

end

élément.rb

class Item < ActiveRecord::Base

  def as_json(options)
    options = { :only => [:id, name], :methods => [:zim, :gir] }.merge(options)
    super(options)
  end

end

home_controller.rb

class HomeController < ApplicationController

  def observe
    @items = Items.find(...)
    respond_to do |format|
      format.js do
        render :json => {
          :user => current_user || {},
          :items => @items
        }
      end
    end
  end

end

OriginalL'auteur maček | 2010-04-03