【问题标题】:Rails 3.2 - Why does overriding [] muddle up has_many relationships?Rails 3.2 - 为什么覆盖 [] 会混淆 has_many 关系?
【发布时间】:2013-02-28 01:55:05
【问题描述】:

我正在努力将旧版 Rails 应用程序从 3.0 升级到 3.2,并且遇到了一些来自 ActiveRecord 的非常令人费解的行为。我有两个非常简单的模型:

class Newsletter < ActiveRecord::Base
  has_many :newsletter_entries

  def [](key)
    # Weird old code, not related to NewsletterEntry
  end

  # etc.
end

class NewsletterEntry < ActiveRecord::Base
  belongs_to :newsletter

  # etc.
end

在我的 Rails 3.0 分支中,一切正常。但在我的 Rails 3.2 分支中,无论出于何种原因,在时事通讯上调用 newsletter_entries 总是返回空。查看 SQL 语句,很快发现 ActiveRecord 总是在 newsletter_entries 表中搜索 newsletter_id=NULL 的条目,而不管我正在处理的 Newsletter 的实际主键是什么。考虑此控制台输出末尾的 SQL:

> newsletter = Newsletter.create! :title => "Proof of Concept"
### SQL and irrelevant fields omitted
=> #<Newsletter id: 13, title: "Proof of Concept", created_at: "2013-02-28 00:44:25", updated_at: "2013-02-28 00:44:25"> 

> newsletter.newsletter_entries
  NewsletterEntry Load (0.4ms)  SELECT `newsletter_entries`.* FROM `newsletter_entries` WHERE `newsletter_entries`.`newsletter_id` IS NULL
=> [] 

经过大量的哀号和咬牙切齿后,我将问题追溯到 Newsletter 模型上的自定义 [] 方法 - 删除它,一切都恢复正常。这种覆盖一开始就是一种代码味道,现在我知道源代码就可以轻松解决问题了——但是整个事件让我对 [] 在 ActiveRecord 关系中的作用产生了病态的好奇。谁能向我解释这里到底出了什么问题?

【问题讨论】:

    标签: ruby-on-rails-3 activerecord has-many


    【解决方案1】:

    您的Newsletter 类继承自ActiveRecord::Base,它在activerecord/lib/active_record/base.rb 中定义。

    class Base 中包含的模块之一是AttributeMethods,它在activerecord/lib/active_record/attribute_methods.rb 中定义。

    并且定义了方法:

    # activerecord/lib/active_record/attribute_methods.rb
    def [](attr_name)
      read_attribute(attr_name) { |n| missing_attribute(n, caller) }
    end
    

    这就是你的代码破坏 Rails 代码的地方。

    如何找到这个:

    • 克隆 Rails 存储库。
    • 查找所有def []:执行grep -r 'def \[\]' ./activerecord/
    • 找到class Base:执行grep -r 'class Base' ./activerecord/
    • 打开这个类并将所有def [] 搜索结果与class base 中包含的模块进行比较(类本身在activerecord/lib/active_record/base.rb 文件的底部附近定义。

    【讨论】:

    • 这绝对解释了被覆盖的内容,但看起来这种行为早于 Rails 3。我想我真正好奇的是为什么 has_many 定义的关系突然依赖于 Rails-default [ ] 3.1 或 3.2 的方法。话虽如此,在这种情况下,失败更有意义 - 非常感谢。
    • 你可以使用这个命令探索分支之间的变化:git diff -b origin/3-0-stable origin/3-2-stable ./activerecord/lib/active_record/attribute_methods.rb
    猜你喜欢
    • 1970-01-01
    • 2013-01-10
    • 1970-01-01
    • 1970-01-01
    • 2014-01-10
    • 1970-01-01
    • 2013-11-30
    • 2023-04-06
    • 1970-01-01
    相关资源
    最近更新 更多