2013-02-28 60 views
1

我正在將遺留的Rails應用程序從3.0升級到3.2,並且遇到了ActiveRecord中一些令人困惑的行爲。我有兩個非常簡單的模型:Rails 3.2 - 爲什麼重載[]混淆has_many關係?

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的條目,而不管我正在處理的新聞快遞的實際主鍵。考慮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 
=> [] 

很多哀號和咬牙切齒的我追查問題回到在通訊模式自定義[]方法後 - 刪除它,一切都恢復正常。這種重寫是一種代碼味道,我現在可以很容易地解決這個問題,但我知道源代碼 - 但整件事情讓我對[]在ActiveRecord關係中的角色充滿好奇。任何人都可以向我解釋究竟出了什麼問題嗎?

回答

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文件的底部定義的類
+0

。這絕對可以解釋什麼是重寫,但看起來行爲早於Rails 3.我想我真正好奇的是爲什麼由has_many定義的關係突然依賴於3.1或3.2中的Rails-default []方法。那據說,在這種情況下失敗會更有意義 - 非常感謝。 – Andrew 2013-03-07 05:23:26

+0

您可以使用以下命令探究分支之間的變化:'git diff -b origin/3-0-stable origin/3-2-stable ./activerecord/lib/active_record/attribute_methods.rb' – 2013-03-07 06:04:53