activerecord-importで、子レコードの同時インサートが出来ない問題

f:id:ryoutaku_jo:20190410200658p:plain

【結論】

MySQLの場合、activerecord-importでは、
 子レコードの同時インサートが出来ない。
 (PosgreSQLでは可能)

・子レコードも同時にDBへ保存する場合は、
 トランザクションをロックして、IDを紐付けた後に、
 子レコードを別途バルクインサートする必要がある。

【目次】

【本題】

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

《今日の学習進捗(3年以内に10000時間に向けて)》

学習開始からの期間 :124日
今日までの合計時間:1179h
一日あたりの平均学習時間:9.6h
今日までに到達すべき目標時間:1132h
目標との解離:47h
「10,000時間」まで、

残り・・・「8821時間!」