Rails 从多态模型中加入或预加载 own_to 关联

发布于 2024-11-03 19:01:06 字数 997 浏览 5 评论 0 原文

我的问题如下。我怎样才能从多态模型加入belongs_to关联

有情况

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:如果不指定多态类,则无法创建多态Belongs_to连接!

我如何具体说明我想加入哪个班级?

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

Opinion.preload(:opinionable).all

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

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

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

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

那么我怎样才能做类似的事情

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

?

谢谢,大卫!

my problem is following. How can I joins belongs_to association from polymorphic model

There is situation

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

How can i do following

Opinion.joins(:opinionabe).all

it will throw

ArgumentError: You can't create a polymorphic belongs_to join without specifying the polymorphic class!

How can i specific which class i want to join?

Second question. How to preload it?

Opinion.preload(:opinionable).all

works fine. It will do query for each class in belongs_to.

But. if i want to do something like

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

there is problem because one model has this association and second hasn't. So it will throw exception.

So how i can do something like

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

?

Thanks, David!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

大海や 2024-11-10 19:01:06

事实上,如果你这样做

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

,你就可以做到

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

Actually if you just do

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

then you can do

Opinion.joins(:opinionable_answer).where(answers: { awesome: true})
孤独难免 2024-11-10 19:01:06

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

It looks like you have not specified opinionable_type:string column for your Opinion model.

Try to update your migration in this manner:

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

This will solve your second question and Opinion.preload(:opinionable).all should work well.

You cann't do joins on polymorphic association because they can be located in different tables, which are detected after Opinion model is loaded. That why model needs column opinionable_type.

If you try to do this you'll get next exception

ActiveRecord::EagerLoadPolymorphicError: Can not eagerly load the polymorphic association :opinionable

UPD: Added magic join ^_^

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

Example:

Opinion.by_type(Answer).to_sql
  => "SELECT \"opinions\".* FROM \"opinions\" JOIN answers ON answers.id = opinions.opinionable_id AND opinions.opinionable_type = 'Answer'" 
你对谁都笑 2024-11-10 19:01:06

我知道这个问题已经很老了,但我只花了一个小时寻找类似问题(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

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

加入(答案::other_model)

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

希望它对某人有帮助!

I know this question is old but I just spent an hour looking for the solution to a similar problem (Rails 3) and the only way I got it to work was the solution stated here: https://stackoverflow.com/a/25966630/6878997

Which, in your case would be:

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

Seems tricky but this way you will be able to do multiple chained joins such as:

joins(answer: :other_model).

And whenever opinion.opinionable is not an Answer, opinion.answer will return nil.

Hope it helps somebody!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文