как получить все экземпляры объектов по полиморфному типу?

#ruby-on-rails

#ruby-на-рельсах

Вопрос:

У меня настроены следующие модели:

 class Sound < ActiveRecord::Base  
  has_many :tenders, :as => :tenderable
  belongs_to :event
end

class Stage < ActiveRecord::Base
  has_many :tenders, :as => :tenderable
  belongs_to :event
end

class Tender < ActiveRecord::Base
  attr_accessible :event_id, :user_id, :estimate, :tenderable_id, :tenderable_type
  belongs_to :tenderable, :polymorphic => :true
end

class Event < ActiveRecord::Base
  attr_accessible :name
  has_one :stage
  has_one :sound

  accepts_nested_attributes_for :stage, :allow_destroy => true
  accepts_nested_attributes_for :sound, :allow_destroy => true
end
 

К каждому событию привязаны различные тендерные предложения (например, сцена, звук), я могу получить к ним доступ через Event.find(id).tenderables, но мне нужно определить, какие «возможности» доступны независимо от события, к которому они привязаны.

На данный момент у меня нет модели для «Возможности», поскольку я пытаюсь упростить задачу.

На самом деле то, что я хочу сделать, — это что-то вроде нежных блюд.все это вернет все «Звуки», «Сцены» и все остальное, что я определяю как «приемлемое».

Каков наилучший способ добиться этого?

Спасибо 😉

Комментарии:

1. Вы хотите найти все Tenderables , у которых есть a Tender , или все объекты, которые могли бы получить a Tender (потому что это было бы просто все Stages, Sounds, ... ).

2. Привет, Натанвда — мне нужны все объекты, которые могли бы получить тендер. список «нежных» сцен, звуков, … список, вероятно, будет регулярно меняться….

Ответ №1:

 Tender.select("DISTINCT tendable_type").collect(amp;:tendable_type).compact
 

Выдаст вам названия всех связанных моделей, которые уже использовались хотя бы один раз.

Для всех объектов, которые были связаны как управляемые

 Tender.where("tendable_type IS NOT NULL").collect(amp;:tendable)
 

Комментарии:

1. Как я читал, OP ищет не имена моделей, а объекты.

2. Этот ответ правильный, но имеет проблемы с производительностью. Я опубликовал еще один ответ для их решения.

Ответ №2:

Afaik список всех Tenderables , в смысле вещей, которые могут быть Tender привязаны к нему, невозможно построить из базы данных или структуры модели. В базе данных вы сможете найти все Tenderable , к которым Tender подключен a, но не простым способом (подумайте об объединении запросов для каждого tenderable_type ).

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

Я не совсем уверен, зачем вам это нужно, но вы должны выполнить объединение Sound.all and Stage.all и любой таблицы, которая станет доступной позже.

Теперь, когда я пишу это, я думаю: чтобы иметь возможность выполнять объединение, эти таблицы должны быть очень похожи. Если это так, в вашем случае вам может потребоваться ввести Tenderable объект по-настоящему и использовать STI. Для того, что вы хотите прямо сейчас, это было бы лучшим решением.

Все, что есть Tenderable , должно помещаться в одну таблицу с типом (звук, сцена, …), а затем вы получаете нормальное отношение к тендерному. Сцена или звук наследуются от Tenderable. Затем вы можете легко выбрать все Тендерабли или все звуки / этапы отдельно.

Надеюсь, это поможет.

Комментарии:

1. Я пометил ответ Дэвида правильным, поскольку он, вероятно, более полезен для других пользователей — хотя этот был наиболее полезен для моего понимания ситуации! Большое спасибо! 🙂

2. Нет необходимости объяснять: вы определяете, какой ответ работает лучше всего, и другие пользователи тоже решат (проголосовав за вопрос, который им больше нравится).

Ответ №3:

Принятый ответ правильный, но неэффективный.

  1. Чтобы выбрать все типы:

Tender.distinct.pluck(:tendable_type)

Это выполняет больше работы в базе данных и не требует создания экземпляра каждого уникального объекта для вызова метода для него.

  1. Чтобы выбрать все объекты:

Tender.where.not(tendable: nil).includes(:tendable).map(amp;:tendable)

Это приложение загружает данные ассоциации сразу, а не при каждом запуске цикла. Это все равно загрузит каждую запись в память, но может быть значительно более производительным в зависимости от количества имеющихся у вас записей. Принятый ответ попадет в базу данных при каждом запросе.