【问题标题】:Rails joins or preload belongs_to association from polymorphic modelRails 从多态模型加入或预加载belongs_to 关联
【发布时间】:2011-08-14 11:33:37
【问题描述】:

我的问题如下。如何从多态模型加入belongs_to 关联

有情况

意见.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: You can't create a polymorphic belongs_to join without指定多态类!

如何确定我想参加哪个课程?

第二个问题。如何预加载?

Opinion.preload(:opinionable).all

工作正常。它将查询belongs_to中的每个类。

但是。如果我想做类似的事情

Opinion.preload(:opinionable => :answer_form).all

存在问题,因为一个模型具有此关联,而第二个模型没有。所以它会抛出异常。

那么我该怎么做呢

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

?

谢谢,大卫!

【问题讨论】:

    标签: ruby-on-rails activerecord join preload polymorphism


    【解决方案1】:

    您似乎没有为您的意见模型指定 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'" 
    

    【讨论】:

    • Polyporhic 对我来说很好用(在表中有 id 和 type 列)。得到你的解释为什么加入不起作用。我错过了模型不知道属于哪些类的事实。
    • 有想法。如果我知道类 Opinion.joins([:opinionable, Answer]) 可能是这样的吗?
    • 如果你知道具体的类,你可以在 Opinion 模型中添加类似:belongs_to :opinionable_answer, :foreign_key =&gt; :opinionable_id, :class_name =&gt; "Answer" 的内容。然后Opinion.joins(:opinionable_answer) 应该可以正常工作。
    • 这不起作用,因为它会通过 id 加入 Answer 表,这些 id 也适用于另一个所属模型。查询是SELECT opinions.* FROM opinions INNER JOIN answers ON answers.id = opinions.opinionable_id,但我需要添加才能加入此JOIN ... ON ... AND opinions.opinionable_type = 'Answer'
    【解决方案2】:

    其实你只是这样做

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

    那你就可以了

    Opinion.joins(:opinionable_answer).where(answers: { awesome: true})
    

    【讨论】:

    • 谢谢!按预期工作:)
    【解决方案3】:

    我知道这个问题很老,但我只花了一个小时寻找类似问题的解决方案(Rails 3),我让它工作的唯一方法是这里说明的解决方案:https://stackoverflow.com/a/25966630/6878997

    在你的情况下是:

    class Opinion < ActiveRecord::Base
      # The true polymorphic association
      belongs_to :opinionable, polymorphic: true
    
      # The trick to solve this problem
      has_one :self_ref, :class_name => self, :foreign_key => :id
    
      has_one :answer, :through => :self_ref, :source => :opinionable, :source_type => Answer
    end
    

    看起来很棘手,但这样你就可以进行多个链式连接,例如:

    joins(answer: :other_model).

    只要opinion.opinionable 不是Answeropinion.answer 就会返回nil

    希望它对某人有所帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多