значения по умолчанию для to_json в Rails с: include - PullRequest
25 голосов
/ 15 февраля 2011

Допустим, у меня есть модельное сообщение, принадлежащее пользователю. Чтобы преобразовать в JSON, я делаю что-то вроде этого

@reply.to_json(:include => {:user => {:only => [:email, :id]}, 
               :only => [:title, :id])

Однако я хочу установить для этого некоторые значения по умолчанию, поэтому мне не нужно указывать: только каждый раз. Я пытаюсь переопределить as_json для достижения этой цели. Когда я добавляю as_json в модель User, он вызывается, когда я делаю @ user.to_json, но когда пользователь включен в @ reply.to_json, мой переопределенный as_json для пользователя игнорируется.

Как мне сделать эту работу?

Спасибо

Ответы [ 5 ]

33 голосов
/ 10 марта 2012

Вы можете сделать это, переопределив serializable_hash в вашей модели, например:

class Reply < ActiveRecord::Base
  def serializable_hash(options={})
    options = { 
      :include => {:user => {:only => [:email, :id]}, 
      :only => [:title, :id]
    }.update(options)
    super(options)
  end
end

Это повлияет на все сериализуемые методы, включая serializable_hash, to_json и to_xml.

3 голосов
/ 19 августа 2011

В модели ответа:

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

И в модели пользователя:

def as_json(options = {})
   super options.merge(:only => [:id, :email])
end

Когда ассоциация включена как метод, а не как включение, он запустит.to_json на нем.

0 голосов
/ 16 февраля 2011

Итак, я обнаружил, что проблема в том, что для include вместо вызова as_json для генерации json Rails напрямую вызывает serializable_hash. Исправление обезьян устраняет проблему. Поместите это в инициализатор

module ActiveRecord #:nodoc:
  module Serialization

    def serializable_hash(options = nil)
      options = options.try(:clone) || {}

      options[:except] = Array.wrap(options[:except]).map { |n| n.to_s }
      options[:except] |= Array.wrap(self.class.inheritance_column)

      hash = super(options)

      #serializable_add_includes(options) do |association, records, opts|
        #hash[association] = records.is_a?(Enumerable) ?
        #records.map { |r| r.serializable_hash(opts) } :
        #records.serializable_hash(opts)
      #end

      serializable_add_includes(options) do |association, records, opts|
        hash[association] = records.is_a?(Enumerable) ?
          records.map { |r| r.as_json(opts.merge(:no_root => true)) } :
          records.as_json(opts.merge(:no_root => true))
      end

      hash
    end
  end
end

module ActiveModel
  # == Active Model JSON Serializer
  module Serializers
    module JSON

      def as_json(options = nil)
        hash = serializable_hash(options)

        if include_root_in_json and !options[:no_root]
          custom_root = options && options[:root]
          hash = { custom_root || self.class.model_name.element => hash }
        end

        hash
      end

    end
  end
end

Обратите внимание, как вызов serializable_hash заменяется на as_json (с дополнительным параметром для подавления добавления root в include). Теперь, если в вашей модели есть as_json, он будет вызываться даже в случае включений

0 голосов
/ 13 мая 2011

Поскольку при любых обстоятельствах варианты могут быть равны нулю, нам лучше знать об этом:

module ActiveModel
  # == Active Model JSON Serializer
  module Serializers
    module JSON

      def as_json(options)
        options ||= {}
        hash = serializable_hash(options)

        if include_root_in_json and !options[:no_root]
          custom_root = options && options[:root]
          hash = { custom_root || self.class.model_name.element => hash }
        end

        hash
      end

    end
  end
end
0 голосов
/ 15 февраля 2011

Вы можете добавить другой метод в ActiveRecord :: Base, например self.to_minimal_json (* only_fields) и создать там свой вызов .to_json.

не впечатляет, но может работать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...