subclass_from_attributes工作正常吗?

时间:2018-02-02 12:39:41

标签: ruby-on-rails ruby-on-rails-5 rails-activerecord ruby-on-rails-4.2 sti

我有几个继承了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>'

可以清楚地看到,find_sti_class来电时未调出new。我还在我的self.find_sti_class中插入了一些调试输出,但没有调用它。

好的,使用来源,Luke。 转到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

1 个答案:

答案 0 :(得分:0)

你可以......

def self.new(options={})
  options[:provider] = find_sti_class(options[:provider]) if options[:provider]
  super(options)
end