使用 Rails 7
我正在使用单表继承(STI)来存储一些非常简单的关联。源对象使用 has_many 与 STI 模型关联。遵循一些有问题的建议https://stackoverflow.com/a/45681641/1014251我在连接模型中使用多态关系。这确实非常有效,但有一个烦恼:
创建连接模型时,源类型是从根 STI 类获取的,而不是实际的源。
class Guidance < ApplicationRecord
has_many :guidance_details
has_many :themes, through: :guidance_details, source: :detailable, source_type: "Theme"
end
class Detail < ApplicationRecord
has_many :guidance_details, as: :detailable
has_many :guidances, through: :guidance_details
end
class GuidanceDetail < ApplicationRecord
belongs_to :detailable, polymorphic: true
belongs_to :guidance
end
class Theme < Detail
end
如果我创建一个新的 GuidanceDetail 并且不指定
detailable_source
系统会插入父类“Detail”:
guidance_detail = GuidanceDetail.create(guidance: Guidance.first, detailable: Theme.first)
guidance_detail.detailable_type => "Detail"
详细类型应为“主题”。
当前要解决此问题,我必须在每次创建新的 GuidanceDetail 时指定Detailable_type。
我尝试直接指定子对象的 has_many 关联,但得到相同的结果:
class Theme < Detail
has_many :guidance_details, as: :detailable
end
theme = Theme.first
guidance = Guidance.first
guidance.themes << theme
输出:
GuidanceDetail Create (1.3ms) INSERT INTO "guidance_details" ("detailable_id", "guidance_id", "position", "created_at", "updated_at", "detailable_type") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id" [["detailable_id", 11], ["guidance_id", 1], ["position", nil], ["created_at", "2024-11-14 10:24:19.785623"], ["updated_at", "2024-11-14 10:24:19.785623"], ["detailable_type", "Detail"]]
如您所见:“detailable_type”是“Detail”。
我有点困惑,因为
GuidanceDetail
的父类不是Detail
,所以我假设你的意思是Theme
。
根据我的理解(我将删除它,这可以被反驳),为了存储类名
"Theme"
,看来Detail
需要是abstract_class
。
ActiveRecord::Associations::BelongsToPolymorphicAssociation 将
foreign_type
设置为 polymorphic_name
polymorphic_name
定义为:
def polymorphic_name
store_full_class_name ? base_class.name : base_class.name.demodulize
end
base_class
def set_base_class # :nodoc:
@base_class = if self == Base
self
else
unless self < Base
raise ActiveRecordError, "#{name} doesn't belong in a hierarchy descending from ActiveRecord"
end
if superclass == Base || superclass.abstract_class?
self
else
superclass.base_class
end
end
end