2009-12-23 68 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">