実装を見てみる
version: Rails 8.1.2
find_or_create_by!
create_or_find_by!
実装からわかること
1. 実行順序
-
find_or_create_by!:find_by→ レコードが見つからなければcreate_or_find_by! -
create_or_find_by!:create!→ActiveRecord::RecordNotUniqueエラーになればfind_by!
2. ブロックの実行タイミング
-
find_or_create_by!: レコードが存在しない場合のみ -
create_or_find_by!: 毎回
3. トランザクション
create_or_find_by! は内部で transaction(requires_new: true)を使用している
-
requires_new: trueにより、外側のトランザクションがあっても SAVEPOINT が作られる - ユニーク制約違反時は SAVEPOINT までロールバックされ、外側のトランザクションには影響しない
- ブロック内の処理(例: 別テーブルへの INSERT)もロールバック対象になる
4. ユニーク制約
create_or_find_by! はユニーク制約前提のメソッド
- ユニーク制約がないと INSERT が毎回成功し、単なる
create!と同じ動作になる -
find_or_create_by!も内部でcreate_or_find_by!を呼ぶため、ユニーク制約がないとレースコンディション時に重複レコードが作られる可能性がある
| 関連 | ユニーク制約 | 備考 |
|---|---|---|
has_one |
親IDに対してほぼ必ずある | 安心して使える |
has_many |
あるとは限らない | 複合ユニーク制約の有無を確認すべき |
参考