RoR вложен: включить, чтобы включить под-ресурсы в to_xml/to_json
У меня возникла странная ситуация с моделью данных, поэтому, возможно, весь мой подход ошибочен. Вот что я делаю:
У меня есть класс под названием Bird и простой класс Color. Понятно, что у каждой птицы есть две ассоциации to_many для Color, одна для мужских цветов и одна для женских цветов. То, как я справлялся с этим, - использовать модель объединения BirdColoration, которая принадлежит птице и цвету, и имеет дополнительное логическое поле, чтобы определить, является ли окраска для мужчин или женщин. Таким образом, каждая птица на самом деле имеет отношение to_many к BirdColoration, а также to_many to Color: через BirdColoration. Если это звучит разумно, продолжайте чтение. В противном случае остановитесь и скажите мне, почему это неправильно!
Мне нужно, чтобы вываливать стол для птиц как json. Раньше, когда у каждой птицы была только одна ассоциация to_many с цветами, я мог просто использовать: include включить цвета каждой птицы в дампе json. Теперь я включаю BirdColorations в дампе, но мне все равно нужно попасть на цветные модели. Я мог бы отдельно включать цвета и цвета каждой птицы, а затем сопоставлять их во время разбора, но я бы скорее просто включил каждый цвет окраски напрямую. Что-то вроде
format.json { render :json => @birds.to_json(:include => [{:bird_colorations => :color}, :seasons, :habitats, :image_holders]) }
Вышеприведенное не работает. Я думаю, что это должно быть возможно. Может ли кто-нибудь указать мне в правильном направлении, как справиться с этим?
Пока, я просто добавлю каждый цвет и окраску птиц отдельно и сопоставляю их при разборе. По крайней мере, я знаю, что это сработает.
Спасибо!
Ответы
Ответ 1
Я нашел ответ здесь. Синтаксис опции include: to_xml и to_json отличается от синтаксиса для метода find ActiveRecord. Чтобы включить вложенные ресурсы таким образом, вы передаете хэш вместо массива. Правильный вызов метода для меня выглядит следующим образом:
format.json { render :json => @birds.to_json(:include => {:bird_colorations => {:include => :color}, :seasons => {}, :habitats => {}, :image_holders => {}}) }
Сравните с тем, что было в моем вопросе, чтобы увидеть разницу. Для ресурсов, для которых вы не хотите включать под-ресурсы, просто передайте пустой хеш в качестве значения для его символьного имени.
Жить и учиться!
Ответ 2
Если у вас сложная структура JSON, лучше переопределить serializable_hash
или as_json
в вашей модели, чем пытаться сделать все это через render :json
.
Так что-то вроде
def serializable_hash(options = nil)
options ||= {}
bird = {:name => name, ...}
bird[:seasons] = seasons.serilizable_hash
bird[:colors] = ... # whatever complex logic you want to get to the colors
bird
end
Обе функции просто должны возвращать хэш.