#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
, у которых есть aTender
, или все объекты, которые могли бы получить aTender
(потому что это было бы просто все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:
Принятый ответ правильный, но неэффективный.
- Чтобы выбрать все типы:
Tender.distinct.pluck(:tendable_type)
Это выполняет больше работы в базе данных и не требует создания экземпляра каждого уникального объекта для вызова метода для него.
- Чтобы выбрать все объекты:
Tender.where.not(tendable: nil).includes(:tendable).map(amp;:tendable)
Это приложение загружает данные ассоциации сразу, а не при каждом запуске цикла. Это все равно загрузит каждую запись в память, но может быть значительно более производительным в зависимости от количества имеющихся у вас записей. Принятый ответ попадет в базу данных при каждом запросе.