我在rails应用程序中使用single table inheritance,并希望显式设置实例的类型。
我有以下内容;
class Event < ActiveRecord::Base
class SpecialEvent < Event
通过单表继承实现。
SpecialEvent.new
按预期工作,但我希望能够执行
Event.new(:type => 'SpecialEvent')
因此,我可以在应用程序中轻松创建不同的子类型。
但是这不起作用,似乎将:type
设置为nil
,而不是我设置的值;我怀疑这是因为通过调用Event.new
它会覆盖:type
参数。
有没有人有这样做的好方法?
答案 0 :(得分:22)
如果您尝试动态实例化子类型,并且您将类型作为字符串,则可以执行以下操作:
'SpecialEvent'.constantize.new()
答案 1 :(得分:14)
来自“务实 - 使用rails第3版的敏捷Web开发”,第380页
男人,这本书真的很摇滚还有一个不太明显的约束(使用STI)。属性类型 也是内置Ruby方法的名称,因此直接访问它 设置或更改行的类型可能会导致奇怪的Ruby 消息。相反,通过创建对象隐式访问它 适当的类,或通过模型对象的索引访问它 界面,使用如下内容:
person [:type] ='经理'
答案 2 :(得分:5)
不,我想创建的实例 子类型,我想要的地方 以编程方式确定哪个 他们是sub_type - HermanD
你可以使用factory pattern,虽然我最近听说人们对过度使用这种模式感到不满。基本上,使用工厂来创建您想要的实际类型
class EventFactory
def EventFactory.create_event(event_type)
event_type.constantize.new()
end
end
答案 3 :(得分:2)
对我来说,听起来你需要event#create
行动中的一些魔力:
type = params[:event].delete(:type)
# check that it is an expected value!!!
die unless ['Event', 'SpecialEvent'].include(type)
type.constantize.new(params[:event])
答案 4 :(得分:0)
显然,Rails不允许您直接设置Type。这就是我做的......
klass_name = 'Foo'
...
klass = Class.const_get(klass_name)
klass.new # Foo.new
我相信.constantize是一个Rails偏转器快捷方式。 const_get是Class和Module上的Ruby方法。
答案 5 :(得分:0)
预先我会同意STI通常不是处理事情的最佳方式。多态性,是的,但使用多态关联通常比STI更好。
那就是说,我有一个STI很重要的系统。这是一个司法系统,诸如法庭案件之类的事情在其类型上非常相似,并且通常共享其所有基本属性。但是,民事案件和刑事案件在他们管理的要素上存在差异。这发生在系统的几个层面,因此抽象了我的解决方案。
https://github.com/arvanasse/sti_factory
长话短说,它使用工厂方法来利用上述常用方法。因此,控制器可以保持中立/不知道您正在创建的特定类型的STI类。
答案 6 :(得分:0)
您可以使用Rails safe_constantize方法,这将确保对象/类实际存在。
例如:
def typeify(string)
string.classify.safe_constantize
end
new_special_event = typeify('special_event').new