1

所以我最近一直在研究单表继承,并找到了这个常见的问题/答案:

obj问题:在 STI 中,假设 Beta < Alpha,如何将对象的类别从 Alpha 更改为 Beta?

答:ruby 是一种鸭式语言,所以你不用强制转换。但是您需要做的就是将“type”变量设置为“Beta”并保存对象,下次加载 Alpha 对象时,它将是 Beta 类型:

obj = Alpha.new
obj.save #now obj is of type Alpha

obj.type = "Beta"
obj.save #now obj is of type Beta

但是,这种方法似乎对我不起作用。虽然 obj 确实可以正确保存,但它似乎根本不能用作 Beta 对象。它在不运行 Beta 验证的情况下保存,当我检查时obj.respond_to?(:beta_method) #beta_method being a method in the beta class,它返回 false。这种方法不起作用吗?有正确的方法吗?还是我只是做错了什么?

编辑

我发现当我执行 Alpha.last.respond_to(:beta_method) 时它返回 false,而 Beta.last.respond_to(:beta_method) 返回 true(但是 Alpha.last 和 Beta.last 返回相同的对象)。有趣的发展?不过,如果有人能详细解释这一点(关于 ruby​​ 如何处理继承),那就太棒了。

4

2 回答 2

4

根据您要完成的工作,您可能希望becomes像以前一样(或直接通过)使用或更改对象的类型,update_attribute然后从数据库中重新加载它(或两者兼而有之)。

becomes将实例化并返回作为唯一参数传递的类的新对象,使用与前一个对象相同的属性。这将允许您调用新对象的方法。例如:

a = Alpha.last

# if you want to save the new type in the database:
a.type = 'Beta' 
a.save

b = a.becomes(Beta)
b.respond_to?(:beta_method)
=> true

我发现,调用方法的顺序很重要。如果您尝试先使用becomes然后更改类型并保存,则不会更改数据库中的类型。

于 2011-07-27T19:29:25.377 回答
1

正如您所说,Ruby 不允许类型转换。相反,这里发生的是 ActiveRecord 正在实例化不同类的实例,具体取决于type字段的值是什么。因此,当您将其更改为“Beta”时,从 Ruby 的角度来看,您实际上并没有做任何事情。

但是,当 ActiveRecord 在数据库中查找记录时,它会看到新type值并实例化Beta而不是的实例Alpha。这个过程与 Ruby 的关系比它与 ActiveRecord 的关系要小。

根据您的情况,有时会有更优雅的方法。如果您需要将模型从一种类型“转换”为另一种类型(例如 anEmployee变为 a Manager,它具有其他方法),这是一种合理的方法。在其他情况下,使用 mixins 或其他工具可能会更好地实现您的目标。

如果需要,您还可以创建BetafromAlpha属性的临时实例,如下所示:

# obj is an instance of Alpha
obj = Beta.new(obj.attributes)

但在大多数情况下,这同样是一件奇怪的事情。

于 2011-07-27T18:35:01.033 回答