find_or_initialize_byを使ってみる
要約
find_or_initialize_byはRailsのメソッドで、同時にfind_byとnewを行ってくれる。
find_or_initialize_by | Railsドキュメント
モデル.find_or_initialize_by(条件)
find_byで検索してない場合、条件に入れた値を基に新しいインスタンスが生成される。 createではなくnewなので、saveしないと保存されない。
例
Userモデルにid=1のレコードが一個入ってるテーブルで以下実行してみた。
レコードが存在する場合:idで検索 irb(main):001:0> new_user = User.find_or_initialize_by(id:1) User Load (7.0ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1 irb(main):002:0> new_user => #<User id: 1, provider: "email", uid: "test@example.com", allow_password_change: false, name: "テストユーザー", nickname: nil, image: nil, email: "test-user+1@example.com", created_at: "2021-12-12 18:16:56", updated_at: "2021-12-14 08:00:35"> レコードが存在する場合:id以外で検索 irb(main):011:0> new_user = User.find_or_initialize_by(uid:'test@example.com') User Load (2.5ms) SELECT `users`.* FROM `users` WHERE `users`.`uid` = 'test@example.com' LIMIT 1 irb(main):012:0> new_user => #<User id: 1, provider: "email", uid: "test@example.com", allow_password_change: false, name: "テストユーザー", nickname: nil, image: nil, email: "test-user+1@example.com", created_at: "2021-12-12 18:16:56", updated_at: "2021-12-14 08:00:35"> レコードが存在しない場合:idで検索 irb(main):003:0> new_user = User.find_or_initialize_by(id:2) User Load (2.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 2 LIMIT 1 irb(main):004:0> new_user => #<User id: 2, provider: "email", uid: "", allow_password_change: false, name: nil, nickname: nil, image: nil, email: nil, created_at: nil, updated_at: nil> レコードが存在しない場合saveする。validationが走る。 irb(main):005:0> new_user.save! (1.3ms) BEGIN User Exists? (3.7ms) SELECT 1 AS one FROM `users` WHERE `users`.`email` IS NULL AND `users`.`provider` = 'email' LIMIT 1 (1.3ms) ROLLBACK Traceback (most recent call last): 1: from (irb):5 ActiveRecord::RecordInvalid (Validation failed: Password can't be blank, Email can't be blank) レコードが存在しない場合:id以外で検索。検索条件を代入してインスタンス生成される。 irb(main):009:0> new_user = User.find_or_initialize_by(email:'test@example.com') User Load (0.9ms) SELECT `users`.* FROM `users` WHERE `users`.`email` = 'test@example.com' LIMIT 1 irb(main):010:0> new_user => #<User id: nil, provider: "email", uid: "", allow_password_change: false, name: nil, nickname: nil, image: nil, email: "test@example.com", created_at: nil, updated_at: nil>