activerecord-importで、子レコードの同時インサートが出来ない問題
【結論】
・MySQLの場合、activerecord-importでは、
子レコードの同時インサートが出来ない。
(PosgreSQLでは可能)
・子レコードも同時にDBへ保存する場合は、
トランザクションをロックして、IDを紐付けた後に、
子レコードを別途バルクインサートする必要がある。
【目次】
- activerecord-importだと、子レコードが一緒にインサートされない
- activerecord-importで子モデルを同時にインサートする方法
- PosgreSQLのみ、同時インサートに対応
【本題】
activerecord-importだと、子レコードが一緒にインサートされない
前回、「activerecord-import」によるバルクインサートと、
「accepts_nested_attributes_for」による
子レコードの同時保存の方法を紹介しました。
実際の開発においては、
これらを組み合わせた機能を実装したい場面があります。
しかし、「activerecord-import」によるバルクインサートは、
子レコードの同時インサートに対応していません。
activerecord-importで子モデルを同時にインサートする方法
子レコードも同時にインサートしたい場合は
トランザクションをロックして、IDを紐づけたのちに、
子レコードを別にバルクインサートする必要があります。
下記が実装例です。
# トランザクションで、UserRoleのバルクインサートが失敗した場合、ロールバックする様にする User.transaction do # Userをバルクインサート User.import(users) # userにはUserのモデルオブジェクトが配列で格納されているので、eachで1件づつ取り出す users.each do|user| # モデルオブジェクトにはIDが割り振られていないので、DBから引っ張ってくる user = User.find_by(email: user.email) # IDを紐づけて、UserRoleのオブジェクトを生成 user_roles << user.user_roles.build(role_id: "1") end # Userをバルクインサート UserRole.import(user_roles) end
PosgreSQLのみ、同時インサートに対応
なお、PosgreSQLの場合は、「recursive: true」という
オプションを設定する事で、関連モデルも同時にインサートが可能です。
User.import(users), recursive: true