在ActiveRecord中更改对象的类

时间:2010-07-09 17:30:48

标签: ruby activerecord

假设我的数据库中有一个FireNinja < Ninja对象,使用单表继承存储。后来,我意识到他真的是WaterNinja < Ninja。将他改为不同的子类最干净的方法是什么?更好的是,我想创建一个新的WaterNinja对象,只需替换数据库中的旧FireNinja,保留ID。

修改 我知道如何从现有的WaterNinja创建新的FireNinja对象,我也知道我可以删除旧的{{1}}并保存新的对象。我想做的是 mutate 现有项目的类。我是通过创建一个新对象并做一些ActiveRecord魔术来替换行,或者通过对对象本身做一些疯狂的事情,或者甚至通过删除它并重新插入相同的ID来做到这一点是问题的一部分。

4 个答案:

答案 0 :(得分:8)

您可以通过

让FireNinja充当WaterNinja
@ninja.becomes(WaterNinja)

如果要永久更改类,则只需覆盖type属性。

@ninja.type = "WaterNinja"
@ninja.save!

答案 1 :(得分:2)

你需要做两件事:

  • 创建WaterNinja < Ninja
  • ninjas表中运行类似UPDATE ninjas SET (type = 'WaterNinja') WHERE (type = 'FireNinja')
  • 的内容

就是这样。

对于进行运行时转换,这样做,但我不建议。

class Ninja
  def become_another_ninja(new_ninja_type)
    update_attribute(:type, new_ninja_type)
    self.class.find(id)
  end
end

@water_ninja = @fire_ninja.become_another_ninja('WaterNinja')

问题在于@fire_ninja现在将成为一次性对象。

答案 2 :(得分:0)

支持组合而不是继承 - 您应该使用策略模式在运行时更改此类行为。

http://en.wikipedia.org/wiki/Strategy_pattern

答案 3 :(得分:-1)

您必须定义WaterNinja#to_fireninja方法。 Ruby无法更改对象的类,同时保持对象的相同对象。

class WaterNinja < Ninja
  def to_fireninja
    FireNinja.new :name => name
  end
end