Ruby on Rails:: включайте в полиморфную связь с подмоделями

При работе с полиморфной ассоциацией действительно ли возможно выполнить включение в подмодели, которые только присутствуют в некоторых типах?

Пример:

class Container
  belongs_to :contents, :polymorphic => true
end
class Food
  has_one :container
  belongs_to :expiration
end
class Things
  has_one :container
end

В представлении я собираюсь хотеть сделать что-то как:

<% c = Containers.all %>
<% if c.class == Food %>
  <%= food.expiration %>
<% end %>

Поэтому я хотел бы к нетерпеливой загрузке истечения, когда я загружаюсь c, потому что я знаю, что мне будет нужен каждый последний из них. Там какой-либо путь состоит в том, чтобы сделать так? Просто определение постоянного клиента: включайте получает меня ошибки, потому что не все вложенные типы имеют истечение подмодели.

10
задан tereško 9 February 2013 в 20:18
поделиться

1 ответ

Отредактированный ответ

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

class Container
  belongs_to :content, :polymorphic => true
end

Теперь запросите Container по container_type.

containers_with_food = Container.find_all_by_content_type("Food", 
                           :include => :content)

containers_with_thing = Container.find_all_by_content_type("Thing", 
                           :include => :content)

Старый ответ

Это хак, поскольку нет прямого способа включить полиморфные объекты в один запрос.

class Container
  belongs_to :contents, :polymorphic => true
  # add dummy associations for all the contents.
  # this association should not be used directly
  belongs_to :food
  belongs_to :thing
end

Теперь запросите Container по container_type.

containers_with_food = Container.find_all_by_content_type("Food", 
                           :include => :food)

containers_with_thing = Container.find_all_by_content_type("Thing", 
                           :include => :thing)

Это приводит к двум SQL-запросам к базе данных (на самом деле это 4 запроса, так как rails выполняет один SQL для каждого :include)

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

Предостережение: Фиктивные ассоциации на классе Content не следует использовать напрямую, так как это приведет к неожиданным результатам.

Например: Допустим, первый объект в таблице contents содержит еду.

Content.first.food # will work
Content.first.thing

Второй вызов не сработает. Он может дать вам объект Thing с тем же id, что и объект Food, на который указывает Content.

24
ответ дан 3 December 2019 в 16:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: