【问题标题】:subclass_from_attributes works fine?subclass_from_attributes 工作正常吗?
【发布时间】: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


    【解决方案1】:

    你可以...

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

    【讨论】:

    • 所以,这是一个已知的错误,有人知道吗?我对此一无所知(可能搜索得很糟糕),但我不能成为第一个尝试这样做的人
    • 此外,此解决方案将创建具有类名的对象,例如A::Bprovider 列中,而不是预期的a_b
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-22
    • 1970-01-01
    • 2013-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多