Ruby on rails ActiveRecord派生的属性持久性,取决于id值

Ruby on rails ActiveRecord派生的属性持久性,取决于id值,ruby-on-rails,activerecord,Ruby On Rails,Activerecord,如何持久化依赖于rails中id值的派生属性?下面的代码片段似乎有效——有更好的rails方法吗 class Model < ActiveRecord::Base .... def save super #derived_attr column exists in DB self.derived_attr = compute_attr(self.id) super end end 类模型正确 >>五 => # >>最后一个 => # 我认为更普

如何持久化依赖于rails中id值的派生属性?下面的代码片段似乎有效——有更好的rails方法吗

class Model < ActiveRecord::Base
  ....
  def save
    super
    #derived_attr column exists in DB
    self.derived_attr = compute_attr(self.id)
    super
  end
end
类模型
提供了回调,因此您不必重写save。下面代码中的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
类模型
提供了回调,因此您不必重写save。下面代码中的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
类模型
我认为更普遍的方法是为虚拟属性提供一个自定义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
class-Virt
在控制台中运行此命令将显示以下内容

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">
v=Virt.new
=> #
>>v.保存
=>正确
>>五
=> #
>>最后一个
=> #

我认为更普遍的方法是为虚拟属性提供一个自定义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
class-Virt
在控制台中运行此命令将显示以下内容

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">
v=Virt.new
=> #
>>v.保存
=>正确
>>五
=> #
>>最后一个
=> #

我假设他在DB中有一个名为virtual_attr的列,该列基于ID。可以是,但通常属性是虚拟的,因为它们没有相应的DB列。它们通常是从现有列派生的。说到Rails,我从来没有听说过任何其他虚拟属性的定义。很好。我重新表述了使用派生属性而不是虚拟属性的问题。感谢您指出Chandra,我更新了我的答案以解决这一新的发展。我认为Steve的解决方案更好,至少对于可能不是id的派生属性的更一般情况而言,因为只要基础字段发生更改,就可以使用正确的virtual_attr值。在这种特定的情况下,如果基础字段是永不更改的id,那么就没有那么重要了。我假设他在DB中有一个名为virtual_attr的列,该列基于id。可以是,但通常属性是虚拟的,因为它们没有对应的DB列。它们通常是从现有列派生的。说到Rails,我从来没有听说过任何其他虚拟属性的定义。很好。我重新表述了使用派生属性而不是虚拟属性的问题。感谢您指出Chandra,我更新了我的答案以解决这一新的发展。我认为Steve的解决方案更好,至少对于可能不是id的派生属性的更一般情况而言,因为只要基础字段发生更改,就可以使用正确的virtual_attr值。在这种特定情况下,如果基础字段是永不更改的id,那么它就不那么重要了。