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

【結論】

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