ActiveRecord模型'类型'多态关联列包括关联模型的名称空间

时间:2016-05-15 20:05:34

标签: ruby-on-rails activerecord

问题

在存储/查询关联类型列时,如何告诉ActiveRecord不包含关联类的命名空间?

目前的状况:

考虑以下类定义:

class PageTemplateA < ActiveRecord::Base
  has_many :type_a_pages, :as => :pageable, :class_name => 'TypeAPage', :inverse_of => :pageable
end

##### The following class is implemented through STI.
class TypeAPage < Page
  belongs_to :pageable, :class_name => 'PageTemplateA', :inverse_of => :type_a_page
end

class Page < ActiveRecord::Base
  belongs_to :pageable, :polymorphic => true
end

总结:

  • TypeAPage是通过数据库表pages中的STI实现的。
  • TypeAPage通过多态关联与PageTemplateA相关联(pages.pageable_typePageTemplateA关联时为PageTemplateA

我想做的改变:

我想将上述所有模型移到新的命名空间中,比如PagesEngine,所以我对PageTemplateA的定义如下:

module PagesEngine
  class PageTemplateA < ActiveRecord::Base
    has_many :type_a_pages, :as => :pageable, :class_name => 'TypeAPage', :inverse_of => :pageable
  end
end

这很好,除了,ActiveRecord推断pageable_type的{​​{1}}为TypeAPage

如何告诉ActiveRecord不包含命名空间,并将PagesEngine::PageTemplateA解析为pageable_type而不是PageTemplateA

2 个答案:

答案 0 :(得分:2)

对于包含多态关系的模型,您可以设置self.store_full_sti_class = false或从将store_full_sti_class设置为false的抽象模型继承。

module PagesEngine
  class Page < Base
    # self.store_full_sti_class = false
    belongs_to :pageable, polymorphic: true
  end

  class TypeAPage < Page
    belongs_to :pageable, 
               class_name: 'PageTemplateA', 
               inverse_of: :type_a_pages
  end
end

将关系(type_as_pages)与匹配关联模型(PagesEngine :: PageTemplateA)但没有命名空间的类型列(pageable_type)明确地作用范围。

module PagesEngine
  class PageTemplateA < Base
    has_many :type_a_pages, 
             -> { where(pageable_type: 'PageTemplateA') }, 
             foreign_key: :pageable_id, 
             inverse_of: :pageable
  end
end

最后覆盖belongs_to方法并定制Active Record Belongs To Polymorphic Association。

module PagesEngine
  class Base < ActiveRecord::Base
    self.abstract_class = true
    self.store_full_sti_class = false

    def self.belongs_to(name, scope = nil, options = {})
      super(name, scope, options).tap do |hash|
        reflection = hash[name.to_s]
        def reflection.association_class
          if polymorphic?
            BelongsToPolymorphicAssociation
          else
            super
          end
        end unless store_full_sti_class
      end
    end
  end

  class BelongsToPolymorphicAssociation < ActiveRecord::Associations::BelongsToPolymorphicAssociation
    def klass
      type = owner[reflection.foreign_type]
      type.presence && PagesEngine.const_get(type)
    end
  end
end

答案 1 :(得分:-1)

使用self.sti_name覆盖相应类的类型列名称:

module PagesEngine
  class PageTemplateA < ActiveRecord::Base
    def self.sti_name
      "PageTemplateA"
    end
  end
end

您可能会发现以下博文有用:https://lorefnon.me/2014/07/27/optimizing-sti-columns.html