Rails присоединяется или предварительно загружается принадлежащим к полиморфной модели - PullRequest
13 голосов
/ 28 апреля 2011

моя проблема заключается в следующем. Как я могу вступить в принадлежащую ассоциацию из полиморфной модели

Есть ситуация

opinion.rb

class Opinion < ActiveRecord::Base
    belongs_to :opinionable, :polymorphic => true
    belongs_to :category
end

answer.rb

class Answer < ActiveRecord::Base
    has_many :opinions, :as => :opinionable
end

Как я могу сделать следующее

Opinion.joins (: opinionabe) .all

бросит

ArgumentError: Вы не можете создать полиморфное объединение own_to без указания полиморфного класса!

Как определить, к какому классу я хочу присоединиться?

Второй вопрос. Как его предварительно загрузить?

Opinion.preload (: opinionable) .all

отлично работает. Это сделает запрос для каждого класса в принадлежащих_ *. 1031 *

Но. если я хочу сделать что-то вроде

Opinion.preload (: мнение) => форма ответа). Все

есть проблема, потому что одна модель имеет эту связь, а вторая - нет. Так что скинут исключение.

Так, как я могу сделать что-то вроде

Opinion.preload (: answer =>: answer_form,: another_belongs_to_model) .all

Спасибо, Дэвид!

Ответы [ 2 ]

15 голосов
/ 08 августа 2012

На самом деле, если вы просто делаете

belongs_to :opinionable_answer, :foreign_key => :opinionable_id, :class_name => "Answer", conditions: { opinions: { opinionable_type: "Answer"}}

тогда вы можете сделать

Opinion.joins(:opinionable_answer).where(answers: { awesome: true})
14 голосов
/ 28 апреля 2011

Похоже, вы не указали столбец opinionable_type:string для своей модели мнения.

Попробуйте обновить миграцию следующим образом:

class CreateOpinions < ActiveRecord::Migration
  def self.up
    create_table :opinions do |t|
      t.integer :opinionable_id
      t.string  :opinionable_type

      # ... other fields

      t.timestamps
    end
  end

  def self.down
    drop_table :opinions
  end
end

Это решит ваш второй вопрос иOpinion.preload(:opinionable).all должно работать хорошо.

Вы не можете выполнять объединения при полиморфной ассоциации, поскольку они могут находиться в разных таблицах, которые обнаруживаются после загрузки модели Opinion.Именно поэтому для модели необходим столбец opinionable_type.

Если вы попытаетесь это сделать, вы получите следующее исключение

ActiveRecord::EagerLoadPolymorphicError: невозможно загружать полиморфную ассоциацию :opinionable

UPD: добавлено магическое соединение ^ _ ^

class Opinion < ActiveRecord::Base
  belongs_to :opinionable, :polymorphic => true

  belongs_to :opinionable_answer, :foreign_key => :opinionable_id, :class_name => "Answer"

  scope :by_type, lambda { |type| joins("JOIN #{type.table_name} ON #{type.table_name}.id = #{Opinion.table_name}.opinionable_id AND #{Opinion.table_name}.opinionable_type = '#{type.to_s}'") }
end

Пример:

Opinion.by_type(Answer).to_sql
  => "SELECT \"opinions\".* FROM \"opinions\" JOIN answers ON answers.id = opinions.opinionable_id AND opinions.opinionable_type = 'Answer'" 
...