関連モデルの作成中に不必要なロードを回避するにはどうすればよいですか?
概要
私の Rails アプリには、これに似たモデルがいくつかあります。
class Pen < ActiveRecord::Base
has_one :ink
after_create :add_ink
def add_ink
create_ink(color: "blue")
end
end
class Ink < ActiveRecord::Base
belongs_to :pen
end
コントローラーでは次のようなことを行います
pen = Pen.new(..)
pen.save
概念的には、ペンには常にインクがあり、ペンの作成時にインクも作成されます。 (これを達成するための after_create フックよりも優れた方法にもオープンです)。
問題は、関連付けには何もないことが保証されているにもかかわらず、関連付けに対して常に SELECT を発行していることです。
[DEBUG] TRANSACTION (0.2ms) BEGIN
[DEBUG] Pen Create (1.5ms) INSERT INTO pens ("owner_id") VALUES ('00f74077-c079-4482-aa03-15b23951a7bd') RETURNING "id"
[DEBUG] Ink Load (0.4ms) SELECT "inks".* FROM "inks" WHERE "inks"."pen_id" = '93a45bae-2cf3-48c1-ac00-6b3059dca5ae' LIMIT 1
[DEBUG] Ink Create (0.3ms) INSERT INTO "inks" ("pen_id", "color") VALUES ('93a45bae-2cf3-48c1-ac00-6b3059dca5ae', 'blue') RETURNING "pen_id"
[DEBUG] TRANSACTION (0.2ms) COMMIT
具体的には、このようなことは起こらないはずです
[DEBUG] Ink Load (0.4ms) SELECT "inks".* FROM "inks" WHERE "inks"."pen_id" = '93a45bae-2cf3-48c1-ac00-6b3059dca5ae' LIMIT 1
build_association の後に save、create_association を使用したり、Association.create で association= を使用したりしてみましたが、いずれもある時点で不要な Load が発生します。
解決策
表示されている現象は、after_create で Ink が作成されたときに Pen がすでに永続化されていることが原因で発生します。
ドキュメントから
したがって、あなたが見ているのは、Rails が関連するレコードがすでに存在するかどうかを判断し、それに応じて更新できるようにしようとしているということです。
希望する結果に応じて、 Ink.create(pen_id: self.id, color: ‘blue’); を試すことができます。ただし、これを before_create アクションに移動するだけで、おそらくより良い実装になると思います。
class Pen < ActiveRecord::Base
has_one :ink
before_create :add_ink
def add_ink
build_ink(color: "blue")
end
end
ドキュメントによると
したがって、これは before_create であるため、ペンは新しいレコードであるため、データベースにクエリせずにインクも保存する必要があります。