【问题标题】:ActiveRecord, find by polymorphic attributeActiveRecord,通过多态属性查找
【发布时间】:2013-01-23 02:23:44
【问题描述】:

有这个:

class Event < ActiveRecord::Base
  belongs_to :historizable, :polymorphic => true
end

user = User.create!

我可以:

Event.create!(:historizable => user)

但我不能:

Event.where(:historizable => user)
# Mysql2::Error: Unknown column 'events.historizable' in 'where clause'

我必须这样做:

Event.where(:historizable_id => user.id, :historizable_type => user.class.name)

更新

重现问题的代码:https://gist.github.com/fguillen/4732177#file-polymorphic_where_test-rb

【问题讨论】:

  • 我知道如果我正确配置了has_many,我可以做到user.events,但我正在寻找where 的可能性。
  • 刚刚在rails项目中打开了一个bug,看看他们的想法:github.com/rails/rails/issues/9227

标签: ruby ruby-on-rails-3 activerecord active-record-query


【解决方案1】:

这已在 Rails master 中实现,并将在 Rails 4. 谢谢。

——@carlosantoniodasilva

【讨论】:

    【解决方案2】:

    我这样做:

    user.events
    

    这是一个正确的 AR 查询,您可以将其与其他范围和内容链接:

    user.events.where(<your event conditions here>)
    

    编辑:反之,AFAIK 必须指定两个字段(这是有道理的:您可以有一个 id 为 4 的用户和另一个有事件的事物,如派对,也有 id 4)。

    EDIT2:关于“为什么create 工作而where 不工作”:create 比where 更高级,因为前者处理“完整模型”,而后者管理事物数据库表级别。

    1. ActiveRecord 的 create (AFAIK) 使用了 new + update_param 的组合。
    2. update_param 使用模型的 xxxx= 方法分配每个单独的属性。
    3. 在您的示例中,historizable= 是由belongs_to 表达式构建的方法。由于belongs_to“知道”它是多态的,它可以处理类型和id。

    另一方面,当您将哈希传递给where 子句时,那里的参数仅引用数据库字段。 Rails 为“更高级别”的访问提供了范围:

    class Event < ActiveRecord::Base
      ...
    
      scope :by_historizable, lambda { |h| where(:historizable_id => h.id, :historizable_type => h.class.name) }
    
    end
    
    ...
    
    Event.by_historizable(user).where(<your other queries here>)
    

    我听说这可能会在 Rails 4 中改变,where 可能更“智能”。不过我还没查。

    【讨论】:

    • Hola @kikito,检查我在问题中的评论,我知道我可以使用 User has_many 关联来获得相同的结果。但在我的上下文中,这是不可能的,我正在构建一个 gem,我负责 Event 实现,但不是我的代码之外的 historizable 对象实现,所以我不能盲目相信has_many 已正确定义。
    • 关于为什么你需要在where 中指定两个字段但它只适用于create 中的一个对我来说没有意义。在一种方法中使用的相同 magic 可以在相反的方法中使用。
    • Hola @fguillen,我的第一个编辑是我对您在 OP 中的评论的回答。我已添加 EDIT2 以响应您的 cmets 置顶此答案。
    • 感谢您的回答,但我的担忧仍然存在。我不想使用 double 参数 where 因为它很脆弱,因为它使用了未记录的前提,例如_type 参数填充有Class.name,它看起来像填充有Class.name.to_s.camelize:stackoverflow.com/questions/8350037/…(结果相同,但可能不同)
    • “这已在 Rails master 中实现,将在 Rails 4 中可用。谢谢。” @carlosantoniodasilva
    【解决方案3】:

    试试:

    Event.joins(:historizable).where(:historizable => {:historizable_type => user})
    

    【讨论】:

    • Can not eagerly load the polymorphic association :historizable
    猜你喜欢
    • 2011-03-18
    • 1970-01-01
    • 1970-01-01
    • 2011-06-03
    • 1970-01-01
    • 2014-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多