动机
这样做的动机是,我想嵌入关系链中包含的任何模型的序列化。我所做的工作在关系级别起作用,但是如果获得一条记录,则序列化将无法利用我所做的工作。
到目前为止我取得的成就
基本上,我正在使用includes_values
class的方法,该方法ActiveRecord::Relation
仅告诉我到目前为止已包括了哪些内容。即
> Appointment.includes(:patient).includes(:slot).includes_values
=> [:patient, :slot]
为了利用这一点,我使用此初始化程序as_json
在该ActiveRecord::Relation
级别覆盖该方法:
# config/initializers/active_record_patches.rb
module ActiveRecord
class Relation
def as_json(**options)
super(options.merge(include: includes_values)) # I could precondition this behaviour with a config
end
end
end
它的作用是增加对我的选择include
中as_json
关系的方法。
因此,旧的链条:
Appointment.includes(:patient).includes(:slot).as_json(include: [:patient, :slot])
现在可以写,没有最后一个包含:
Appointment.includes(:patient).includes(:slot).as_json
获得相同的结果(Patient
andSlot
模型嵌入在生成的哈希中)。
问题
问题在于,因为该方法includes_values
属于类ActiveRecord::Relation
,所以我无法在记录级别使用它来知道是否includes
已完成调用。
因此,当前,当我从此类查询获取记录并对其进行调用as_json
时,我没有得到嵌入式模型。
而实际的问题是回答:
考虑到发生了什么,如何知道查询链中包含的检索当前记录的模型?
如果我可以回答这个问题,那么我可以使用以下as_json
方法在自己的模型中覆盖该方法:
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
extend Associations
def as_json(**options)
super(options.merge(include: included_models_in_the_query_that_retrieved_me_as_a_record))
end
end
一个想法
我的一个主意是覆盖includes
某个地方(可以在我的初始化程序中直接覆盖ActiveRecord::Relation
该类或我的ApplicationRecord
类)。但是,一旦到达那里,就找不到在该关系产生的记录中“盖章”任意信息的简便方法。
这种解决方案感觉很笨拙,可能还有更好的选择。
class ApplicationRecord < ActiveRecord::Base
def as_json(**options)
loaded_associations = _reflections.each_value
.select { |reflection| association(reflection.name).loaded? }
.map(&:name)
super(options.merge(include: loaded_associations))
end
end
请注意,这仅加载第一级关联。如果是这样的Appointment.includes(patient: :person)
话,:patient
由于:person
嵌套,只会返回。如果您打算使事物递归,请提防循环加载的关联。
值得指出的是,您当前正在合并include: ...
提供的选项。不允许用户选择使用其他包含选项。我建议reverse_merge
改为使用。或在左右交换展示位置{includes: ...}.merge(options)
。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句