動機
その動機は、リレーションチェーンに含まれているモデルのシリアル化を埋め込みたいということでした。私が行ったことはリレーションレベルで機能しますが、1つのレコードを取得すると、シリアル化は私が行ったことを利用できません。
私がこれまでに達成したこと
基本的に私がしているのはincludes_values
、クラスのメソッドを使用することです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
およびSlot
モデルは生成されたハッシュに埋め込まれます)。
問題
問題は、メソッド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
1つのアイデア
私が持っているアイデアの1つは、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
これは第1レベルの関連付けのみをロードすることに注意してください。その場合、がネストされているためAppointment.includes(patient: :person)
、のみ:patient
が返さ:person
れます。物事を再帰的にすることを計画している場合は、循環ロードされた関連付けに注意してください。
指摘する価値があるのは、現在include: ...
、提供されているオプションをマージしていることです。他のインクルードオプションを使用する選択肢をユーザーに与えません。reverse_merge
代わりに使用することをお勧めします。または、配置を入れ替え{includes: ...}.merge(options)
ます。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加