我有一個名爲Exam的「父類」,它有很多Score類的實例。我想在保存一個關聯分數時修改考試實例的屬性。我把所有的課都剝離到這個非常簡單的例子中,這看起來很愚蠢,但是卻以最基本的形式來說明問題。這裏是類。Rails:從關聯對象的回調中更新對象
class Exam < ActiveRecord::Base
has_many :scores
def score_saved
# self.name is now "Software Engineering"
self.name = "#{name}!"
# self.name is now "Software Engineering!"
end
end
class Score < ActiveRecord::Base
belongs_to :exam
belongs_to :course
before_save :trigger_score_saved
def trigger_score_saved
exam.score_saved unless exam.nil?
end
end
然後我運行下面的測試:
class ExamTest < ActiveSupport::TestCase
test "create new exam" do
exam = Exam.new(:name => "Software Engineering 1")
score = exam.scores.build(:grade => 80, :course => courses(:one))
exam.save
# self.name is still "Software Engineering" here
assert_equal "Software Engineering 1!", exam.name
end
end
在代碼中的註釋已經說明問題:考試對象的名稱屬性的更新不會發生。請注意,trigger_score_saved proc會被執行,但新設置的值並不是最終保存到數據庫的值。 如果我在檢查對象本身上定義了before_save :trigger_score_saved
回調,則名稱屬性的確會正確更新。所以這似乎與這樣一個事實有關,即有一個級聯保存正在進行,並且可能保存開始的父檢查對象與score.exam對象不同,我試圖修改該值。
任何人都可以解釋這裏發生了什麼,以及我如何能夠成功地從「子對象」的回調中更新父對象的屬性?
注:
- 我使用的Rails 3和Ruby 1.9.2
- 我試過
update_attribute(:name => "#{name}!")
代替self.name = "#{name}!"
,但都具有相同的效果
非常感謝François!這正是我期待的見解!您是否也可以告訴我在保存其中一個孩子時如何處理更新父對象的正確方法? – 2010-11-03 18:22:55
您已經在使用「正確」的方式。現在的ActiveRecord沒有辦法抓住你正在尋找的實例。你必須重新加載並且安全地玩。我經常在我的測試中調用#reload,尋找最新鮮的值。這經常發生在控制器測試中,我用來設置數據庫的實例與控制器將使用的實例不同,因爲控制器會調用ActiveRecord :: Base#重新找到並獲取新實例化的實例。 – 2010-11-04 03:22:05