2009-12-23 62 views
1

如何堅持依賴於導軌中id值的派生屬性?下面的代碼片段似乎有效 - 是否有更好的導軌方式?取決於id值的ActiveRecord派生屬性持久性

class Model < ActiveRecord::Base 
    .... 
    def save 
    super 
    #derived_attr column exists in DB 
    self.derived_attr = compute_attr(self.id) 
    super 
    end 
end 

回答

5

回調提供,所以你不應該重寫保存。以下代碼中的before_save調用在功能上等同於問題中的所有代碼。

我已將set_virtual_attr公開,以便可以根據需要進行計算。

class Model < ActiveRecord::Base 
    ... 
    # this one line is functionally equivalent to the code in the OP. 
    before_save :set_virtual_attr 
    attr_reader :virtual_attr 

    def set_virtual_attr 
    self.virtual_attr = compute_attr(self.id) 
    end 
    private 
    def compute_attr 
    ... 
    end 
end 
+0

我假設他有一個名爲virtual_attr,在一個數據庫中的列基於ID。 – 2009-12-23 09:32:21

+1

可能是,但通常屬性是虛擬的,因爲它們沒有相應的數據庫列。它們通常來自現有的欄目。當談到Rails時,我從來沒有聽說過任何其他虛擬屬性的定義。 – EmFi 2009-12-23 11:22:33

+0

好點。我已經將這個問題改爲使用派生屬性而不是虛擬屬性。 – 2009-12-23 16:06:00

3

我覺得比較認可的方式做,這是提供虛擬屬性的定製的setter,然後提供一個after_create鉤來設定數值創建記錄後。

下面的代碼應該做你想做的。

class Virt < ActiveRecord::Base 

    def after_create() 
    self.virtual_attr = nil # Set it to anything just to invoke the setter 

    save # Saving will not invoke this callback again as the record exists 
      # Do NOT try this in after_save or you will get a Stack Overflow 
    end 

    def virtual_attr=(value) 
    write_attribute(:virtual_attr, "ID: #{self.id} #{value}") 
    end 
end 

在控制檯運行此顯示了以下

v=Virt.new 
=> #<Virt id: nil, virtual_attr: nil, created_at: nil, updated_at: nil> 

>> v.save 
=> true 
>> v 
=> #<Virt id: 8, virtual_attr: "ID: 8 ", created_at: "2009-12-23 09:25:17", 
      updated_at: "2009-12-23 09:25:17"> 

>> Virt.last 
=> #<Virt id: 8, virtual_attr: "ID: 8 ", created_at: "2009-12-23 09:25:17", 
      updated_at: "2009-12-23 09:25:17">