STI模型的多态关联的不匹配设置和预加载

时间:2015-10-27 14:57:11

标签: ruby-on-rails ruby activerecord

github issue link

让我们看看我们有多态表

class DB::Document < ActiveRecord::Base
  # documentable_type, documentable_id
  belongs_to :documentable, polymorphic: true
end

class DB::Ticket < ActiveRecord::Base
  has_one :document, as: :documentable

  def self.find_sti_class(type_name)
    ActiveSupport::Dependencies.constantize("DB::Ticket::#{sti_type_for(type_name)}")
  end

  self.inheritance_column = :type
  self.store_full_sti_class = false

  def self.sti_name
    self.to_s.split('::').last
  end

end

class DB::Ticket::Train < DB::Ticket
end

class Ticket::Airplain < DB::Ticket
end

当我们设置关联时:

doc = Document.new
doc.documentable = DB::Ticket::Train.first! # docuementable_type will be 'DB::Ticket'

当我们预加载多态关联时:

DB::Ticket.where(id: [1,2]).preload(:document).to_a
# SELECT * FROM documents WHERE documentable_id IN (1,2) AND documentable_type = 'Ticket'

我认为它是因为在association.writer上它使用了base_class的name

module ActiveRecord
  # = Active Record Belongs To Polymorphic Association
  module Associations
    class BelongsToPolymorphicAssociation < BelongsToAssociation #:nodoc:
      ...

        def replace_keys(record)
          super
          owner[reflection.foreign_type] = record.class.base_class.name
        end

      ...
    end
  end
end

并在预加载时使用base_class的sti_name

module ActiveRecord
  module Associations
    class Preloader
      class Association #:nodoc:
        ...

        def build_scope
          scope = klass.unscoped
          ...

          if options[:as]
            scope.where!(klass.table_name => { reflection.type => model.base_class.sti_name })
          end

          ...
        end

        ...
      end
    end
  end
end

为什么sql for preload会生成错误的documentable_type? 这是我在使用STI / polymorhic或ActiveRecord错误时的错误吗?

0 个答案:

没有答案