1

我正在将旧版 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 关系中的作用产生了病态的好奇。谁能向我解释这里到底出了什么问题?

4

1 回答 1

1

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

里面包含的模块之一class BaseAttributeMethods,它在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
于 2013-03-05T07:12:54.577 回答