Добавить виртуальный атрибут для вывода json
Скажем, у меня есть приложение, которое обрабатывает список TODO. В списке завершены и незавершенные предметы. Теперь я хочу добавить два виртуальных атрибута в объект списка; количество готовых и незавершенных предметов в списке. Мне также нужны, чтобы они отображались на выходе json.
У меня есть два метода в моей модели, которые извлекают незавершенные/готовые элементы:
def unfinished_items
self.items.where("status = ?", false)
end
def finished_items
self.items.where("status = ?", true)
end
Итак, как я могу получить количество этих двух методов в моем json файле?
Я использую Rails 3.1
Ответы
Ответ 1
Сериализация объектов в 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
.
Ответ 2
С Rails 4 вы можете сделать следующее -
render json: @my_object.to_json(:methods => [:finished_items, :unfinished_items])
Надеюсь, что это поможет кому-то, кто находится на последней/последней версии
Ответ 3
Другой способ сделать это - добавить это в свою модель:
def attributes
super.merge({'unfinished' => unfinished_items, 'finished' => finished_items})
end
Это также автоматически будет работать для сериализации xml.
http://api.rubyonrails.org/classes/ActiveModel/Serialization.html
Однако имейте в виду, что вам могут понадобиться строки для ключей, поскольку метод не может обрабатывать символы при сортировке ключей в рельсах 3. Но он не сортируется в рельсах 4, поэтому больше не должно быть проблем.
Ответ 4
просто закройте все ваши данные в один хэш, например
render json: {items: items, finished: finished, unfinished: unfinished}
Ответ 5
Я просто подумал, что дам этот ответ всем, как я, который пытался интегрировать это в существующий блок as_json:
def as_json(options={})
super(:only => [:id, :longitude, :latitude],
:include => {
:users => {:only => [:id]}
}
).merge({:premium => premium?})
Просто нажмите .merge({})
в конце вашего super()
Ответ 6
Это будет сделано, не выполняя некоторые уродливые перегрузки. Если вы получили модель List
, например, вы можете поместить ее в свой контроллер:
render json: list.attributes.merge({
finished_items: list.finished_items,
unfinished_items: list.unfinished_items
})
Ответ 7
В качестве Aswin, приведенного выше, :methods
позволит вам вернуть конкретный метод/функцию модели в качестве атрибута json, если у вас сложная ассоциация будет делать трюк, поскольку он добавит функции к существующей модели/ассоциациям: D будет работать как прелесть, если вы не хотите переопределять as_json
Проверьте этот код и обратите внимание, как я использую :methods
, а также :include
[N + Query даже не вариант;)]
render json: @YOUR_MODEL.to_json(:methods => [:method_1, :method_2], :include => [:company, :surveys, :customer => {:include => [:user]}])
Функция Overwritting as_json
будет сложнее в этом сценарии (особенно потому, что вы должны добавить собеседники :include
вручную:/
def as_json(options = { })
end