【Rails】rails db:seedを何度実行してもエラーを発生させない

業務でseedデータを作成する機会があったんですが、実装方法に迷ったので備忘録としてまとめます。

バージョン
  • Ruby 3.0.3
  • Rails 6.1.6.1
記事の信頼性
  • ぼくは独学で未経験から従業員300名以上の自社開発企業へ転職しました。
  • 実務ではVue.jsとRailsを毎日書いています。
  • 初心者や駆け出しエンジニアがつまづくポイントも身をもってよく理解しています。
目次

問題

seedデータを作成する際は、rails db:seedを何度実行してもデータが重複したりエラーが発生したりしないように実装するべきなんですが、そのやり方が分からず、必要以上に時間をかけてしまいました、、。

解決方法

find_or_initialize_by メソッドという、Railsで提供されるActiveRecordメソッドを使うことで、この問題を解決することができました。

find_or_initialize_by メソッドについて、Railsドキュメントには以下の説明がありました。

条件を指定して初めの1件を取得し1件もなければ作成

Railsのコードをみると、find_byメソッドで条件を指定して検索し、結果がfalseならnewメソッドを実行しているようです。

これだけだと微妙なので、具体例ベースで考えます。

Userモデルのseedデータ投入例

users_data = [
  { email: 'user1@example.com', name: 'Alice' },
  { email: 'user2@example.com', name: 'Bob' }
]

users_data.each do |user_data|
  user = User.find_or_initialize_by(email: user_data[:email])
  user.attributes = user_data
  user.save! if user.new_record? || user.changed?
end

find_or_initialize_by メソッドにより、まず以下の処理が行われます。

  • user_data[:email]に一致するレコードがデータベースに存在する場合はそのレコードを返す
  • 存在しない場合は新しいUserインスタンスを返す

※この時点ではデータベースには保存しません。

②次に、user.attributes = user_dataにて、Userオブジェクトのemail属性とname属性がuser_dataから割りあてられます。

③最後に、user.save! if user.new_record? || user.changed?で、↓の2つのどちらかに当てはまる場合のみ、データが保存されます。

  • Userオブジェクトが新しいレコードである
  • 既存のレコードだけどemailnameに変更がある

④あとはrails db:seedコマンドを叩けば、seedデータをUserテーブルに反映できます。

また、最初にデータを投入した後に、一部のseedデータを変更した場合でも、再度rails db:seedを実行すれば、エラーなく更新されます。

捕捉

今回のように「おなじ操作(rails db:seed)を何度実行してもおなじ結果になる特性」を冪等性と言うそうです。

読み方は「べきとうせい」です。

rails db:seed以外だと、POST通信のAPIを実装する際などでも冪等性を考慮する必要があります。

パフォーマンスの注意点

find_or_initialize_by メソッドは便利ですが、、パフォーマンスに要注意です。

find_or_initialize_byメソッドの注意点

大量のデータを扱う場合は各レコードごとにクエリが発行されるため、パフォーマンスに影響を与える可能性があります。

seedデータは基本的に一度投入すればOKですが、頻度が多かったり、あまりにも大量のデータを処理する場合は、insert_allメソッドなど他の手法を検討することも重要です。

※ただしinsert_allメソッドはバリデーションがスキップされてしまいます。要件に合わせて使いわけましょう。

参考:insert_allメソッドのドキュメント

まとめ

find_or_initialize_by メソッドをつかうことで、冪等性を保ちつつseedデータを安全にデータベースへ投入する方法を学びました。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

未経験でSESから従業員300名以上の自社開発企業に転職しました。業務や個人開発で直面した問題や、転職・学習の経験を発信していきます。

コメント

コメントする

目次