【发布时间】:2018-02-02 12:39:41
【问题描述】:
我有几个用 STI 继承的类,并以一种优雅的方式替换了 inheritance_column:
module A
class Base < ActiveRecord::Base
self.inheritance_column = 'provider'
PROVIDERS = {
'a_b' => 'B',
'a_c' => 'C'
}
# STI helpers
def self.find_sti_class(type_name)
"A::#{PROVIDERS[type_name]}".constantize or super(type_name)
end
def self.sti_name
PROVIDERS.invert[name.split("::")[-1]]
end
# end STI helpers
end # class Base
end # module A
# b.rb
module A
class B < A; end
end
# c.rb
module A
class C < A; end
end
对于现有对象,整个事情都很好,但是当我尝试创建一个新对象时,问题就开始了:
A::Base.new(provider: 'a_b')
给我
ActiveRecord::SubclassNotFound: Invalid single-table inheritance type: a_b is not a subclass of A::Base
from /bundler_cache/gems/activerecord-4.2.5.1/lib/active_record/inheritance.rb:215:in `subclass_from_attributes'
from /bundler_cache/gems/activerecord-4.2.5.1/lib/active_record/inheritance.rb:55:in `new'
from (irb):16
from /bundler_cache/gems/railties-4.2.5.1/lib/rails/commands/console.rb:110:in `start'
from /bundler_cache/gems/railties-4.2.5.1/lib/rails/commands/console.rb:9:in `start'
from /bundler_cache/gems/railties-4.2.5.1/lib/rails/commands/commands_tasks.rb:68:in `console'
from /bundler_cache/gems/railties-4.2.5.1/lib/rails/commands/commands_tasks.rb:39:in `run_command!'
from /bundler_cache/gems/railties-4.2.5.1/lib/rails/commands.rb:17:in `<top (required)>'
from bin/rails:4:in `require'
from bin/rails:4:in `<main>'
可以清楚地看出,new 调用中没有调用find_sti_class。我还在我的self.find_sti_class 中插入了一些调试输出,但没有被调用。
好的,使用源,卢克。 去apidock看看:
# File activerecord/lib/active_record/inheritance.rb, line 208
def subclass_from_attributes(attrs)
subclass_name = attrs.with_indifferent_access[inheritance_column]
if subclass_name.present? && subclass_name != self.name
subclass = subclass_name.safe_constantize
unless descendants.include?(subclass)
raise ActiveRecord::SubclassNotFound.new("Invalid single-table inheritance type: #{subclass_name} is not a subclass of #{name}")
end
subclass
end
end
所以,不管我们是否重新定义了sti_name,它仍然希望attributes[inheritance_column] 的值与类名匹配!
它似乎在 Rails 5 中得到修复(正如我在 github 上看到的那样):它调用 find_sti_class,应该可以正常工作。
但在 Rails 4.2 中,它似乎仍然令人困惑。
我是不是误读了什么,或者是真的,在这种情况下,我可以创建继承类的对象的唯一方法是通过直接从此类中调用 #new 来创建它,如下所示:
A::B.new?
【问题讨论】:
标签: ruby-on-rails ruby-on-rails-5 rails-activerecord ruby-on-rails-4.2 sti