Использование jbuilder в rails для создания массива объектов с разными классами

Модель (FirstModel) в моем приложении rails имеет отношение has_many с другой моделью (Item).

class FirstModel < ActiveRecord::Base

  has_many :items, :dependent => :destroy

  def item_array
    a = []
    self.items.each do |item|
      a.push(item.item_thing)
    end
    a
  end
end

Сам предмет принадлежит :item_thing через полиморфную ассоциацию. Метод в FirstModel возвращает массив «элементов», а не объект модели соединения (который относится к классу Item), а item_thing каждого объекта Item, и, следовательно, это массив объектов разных классов (проверено в консоли рельсов, и метод возвращает массив просто отлично)

class Item < ActiveRecord::Base
  belongs_to :item_thing,  :polymorphic => true


end

В моем show.json.jbuilder для FirstModel я хочу взять этот массив «элементов» и использовать разные шаблоны в зависимости от того, к какому классу принадлежит элемент. Следующий путь к файлу — «views/api/items/show.jbuilder».

json.extract! @item, :name

json.items @item.item_array do |item|
  if item.class == 'Book'
    json.partial! 'api/books/show', item
  end
  if item.class == 'Car'
    json.partial! 'api/cars/show', item
  end
end

Пути к шаблонам автомобилей и книг — «views/api/cars/show.json.jbuilder» и «views/api/books/show.json.jbuilder».

Когда я получаю json из приведенного выше шаблона, имя объекта FirstModel видно, массив элементов пуст, тогда как я пытаюсь получить массив хэшей для каждого элемента, отображаемый через соответствующий шаблон.

Спасибо за помощь!


person Nikky    schedule 29.03.2016    source источник


Ответы (2)


Я думаю, что ваш код будет работать, если вы измените строки своего класса на фактические имена классов.

т.е. User, а не "User".

Или вы можете сохранить строки и использовать .class.to_s, что вернет "User" для записи пользователя.

Если вы интересуетесь метапрограммированием, вам могут пригодиться методы constantize, camelify и underscore от activesupport.

person max pleaner    schedule 30.03.2016

Возможно, вы можете просто сделать что-то вроде кода ниже, если правильно назовете свои элементы и части.

json.items @item.item_array do |item|
  json.partial! "api/#{item.class.to_s.pluralize.downcase}/show"
end

В качестве альтернативы вы можете использовать оператор case для item.class.to_s или, как предложил один из других ответов, использовать фактический класс класса вместо имени класса в виде строки.

person Michael Brawn    schedule 30.03.2016