Rails单表inheritance – 显式设置类型的最佳方法是什么?

我在rails应用程序中使用单表inheritance ,并希望显式设置实例的类型。

我有以下几点;

class Event < ActiveRecord::Base class SpecialEvent < Event 

这是通过单表inheritance实现的。

SpecialEvent.new按预期工作,但我希望能够做到这样的事情

 Event.new(:type => 'SpecialEvent') 

所以我可以在应用程序中轻松创建不同的子类型。

但是这不起作用,似乎设置:typenil ,而不是我设置的值; 我怀疑这是因为通过调用Event.new它会覆盖:type参数。

有没有人有这样做的好方法?

如果您尝试动态实例化子类型,并且您将类型作为字符串,则可以执行以下操作:

 'SpecialEvent'.constantize.new() 

来自“实用 – 使用rails第3版的敏捷Web开发”,第380页

还有一个不太明显的约束(使用STI)。 属性类型也是内置Ruby方法的名称,因此直接访问它以设置或更改行的类型可能会导致奇怪的Ruby消息。 相反,通过创建适当类的对象来隐式访问它,或者通过模型对象的索引接口访问它,使用如下所示的内容:

人[:type] =’经理’

伙计,这本书真的很震撼

不,我想创建子类型的实例,我想以编程方式确定它们是哪个子类型 – HermanD

你可以使用工厂模式 ,虽然我最近听说人们对过度使用这种模式感到不满。 基本上,使用工厂来创建您想要获得的实际类型

 class EventFactory def EventFactory.create_event(event_type) event_type.constantize.new() end end 

对我来说,听起来你需要在#create action event#create一些mojo:

 type = params[:event].delete(:type) # check that it is an expected value!!! die unless ['Event', 'SpecialEvent'].include(type) type.constantize.new(params[:event]) 

显然,Rails不允许您直接设置Type。 这就是我做的……

 klass_name = 'Foo' ... klass = Class.const_get(klass_name) klass.new # Foo.new 

我相信.constantize是一个Rails偏转器快捷方式。 const_get是Class和Module上的Ruby方法。

在前面我会同意STI通常不是处理事情的最佳方式。 多态性,是的,但使用多态关联通常比STI更好。

也就是说,我有一个STI很重要的系统。 这是一个司法系统,诸如法庭案件之类的事情在各种类型中非常相似,并且通常共享其所有基本属性。 但是,民事案件和刑事案件在他们管理的要素上存在差异。 这发生在系统的几个层面,因此抽象了我的解决方案。

https://github.com/arvanasse/sti_factory

简而言之,它使用工厂方法来利用上述常用方法。 因此,控制器可以保持中立/不知道您正在创建的特定类型的STI类。

您可以使用Rails safe_constantize方法,该方法将确保对象/类实际存在。

例如:

 def typeify(string) string.classify.safe_constantize end new_special_event = typeify('special_event').new