ActiveRecord派生的属性持久性取决于id值

时间:2009-12-23 07:44:26

标签: ruby-on-rails activerecord

如何持久化依赖于rails中id值的派生属性?下面的片段似乎有用 - 有更好的轨道方式吗?

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

2 个答案:

答案 0 :(得分:5)

提供了回调,因此您永远不必覆盖保存。以下代码中的before_save调用在功能上等同于问题中的所有代码。

我已将set_virtual_attr设为public,以便可以根据需要进行计算。

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

答案 1 :(得分: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">