问题:
在存储/查询关联类型列时,如何告诉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_type
与PageTemplateA
关联时为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
?
答案 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