Добавление виртуального атрибута в вывод json


допустим, у меня есть приложение, которое обрабатывает список задач. В списке есть законченные и незаконченные пункты. Теперь я хочу добавить два виртуальных атрибута к объекту списка; количество готовых и незавершенных элементов в списке. Мне также нужно, чтобы они отображались в выводе json.

У меня есть два метода в моей модели, которая выбирает незаконченное/законченное элементы:

def unfinished_items 
  self.items.where("status = ?", false) 
end 

def finished_items 
  self.items.where("status = ?", true) 
end

Итак, как я могу получить количество этих двух методов в моем выводе json?

Я использую рельсы 3.1

7 52

7 ответов:

сериализация объектов в Rails имеет два шага:

  • первый, as_json вызывается для преобразования объекта в упрощенной хэш.
  • затем, to_json о as_json возвращаемое значение для получения конечной строки JSON.

вы вообще хотите оставить to_json в одиночку, поэтому все, что вам нужно сделать, это добавить свой as_json реализация примерно так:

def as_json(options = { })
  # just in case someone says as_json(nil) and bypasses
  # our default...
  super((options || { }).merge({
    :methods => [:finished_items, :unfinished_items]
  }))
end

вы также можете сделать это, как это:

def as_json(options = { })
  h = super(options)
  h[:finished]   = finished_items
  h[:unfinished] = unfinished_items
  h
end

если вы хотите использовать разные имена для метода резервного значения.

если вы заботитесь о XML и JSON, посмотрите на serializable_hash.

в Rails 4, Вы можете сделать следующее -

render json: @my_object.to_json(:methods => [:finished_items, :unfinished_items])

надеюсь, что это поможет кому-то, кто находится на более поздней / последней версии

еще один способ сделать это-добавить это в свою модель:

def attributes
  super.merge({'unfinished' => unfinished_items, 'finished' => finished_items})
end

Это также будет автоматически работать для сериализации xml. http://api.rubyonrails.org/classes/ActiveModel/Serialization.html Имейте в виду, однако, вы можете использовать строки для ключей, так как метод не может иметь дело с символами при сортировке ключей в rails 3. Но он не сортируется в rails 4, поэтому больше не должно быть проблем.

просто закройте все ваши данные в один хэш, как

render json: {items: items, finished: finished, unfinished: unfinished}

Я просто подумал, что предоставлю этот ответ для всех, кто, как и я, пытался интегрировать это в существующий as_json блок:

  def as_json(options={})
    super(:only => [:id, :longitude, :latitude],
          :include => {
            :users => {:only => [:id]}
          }
    ).merge({:premium => premium?})

просто отлип .merge({}) в конце super()

как Aswin перечисленные выше, :methods позволит вам вернуть метод/функцию конкретной модели в качестве атрибута json, если у вас есть сложные ассоциации, это сделает трюк, так как он добавит функции к существующей модели/assossiations :D он будет работать как шарм, если вы не хотите переопределять as_json

проверить этот код, и, пожалуйста, обратите внимание, как я использую :methods а также :include [N + запрос даже не вариант ;)]

render json: @YOUR_MODEL.to_json(:methods => [:method_1, :method_2], :include => [:company, :surveys, :customer => {:include => [:user]}])

перезаписи as_json функция будет намного сложнее в этом сценарии (особенно потому, что вы должны добавить :include assossiations вручную :/ def as_json(options = { }) end

это будет делать, без необходимости делать некоторые уродливые переопределения. Если у вас есть модель List например, вы можете поместить это в ваш контроллер:

  render json: list.attributes.merge({
                                       finished_items: list.finished_items,
                                       unfinished_items: list.unfinished_items
                                     })