ActiveRecordのfind_or_initialize_byメソッドにブロックを渡したときの挙動

過去に書いたソースコードを読んでいて、仕様を理解するのに手間取ってハマったので、共有のために記事を書いておきます。

find_or_initialize_byメソッドの例

以下のようなコードを見かけたとします。

user = User.find_or_initialize_by(email: 'sample@precena.com') do |user|
  user.last_name = 'サンプル'
  user.first_name = '太郎'
end 

上のコードから、どのような仕様を想像するでしょうか?

筆者は、ユーザーが見つかった場合、または、初期化した場合、どちらもlast_namefirst_nameがそれぞれ、サンプル太郎 に初期化されると思ってしまいました。

しかし、実際の挙動としては、以下でした。

ユーザーが見つかった場合は、ブロック内の処理は実行されず

ユーザーをinitializeした場合は、ブロック内の処理が実行される。

実際に、コードを見てみると、以下のようになっています。

def find_or_initialize_by(attributes, &block)
  find_by(attributes) || new(attributes, &block)
end

コードを見ても、上記の挙動が実装されているのが確認でき、find_byで該当レコードが見つかった場合には、&block 部分が無視されるのが分かります。

本サイトの更新情報は、Twitterの株式会社プレセナ・ストラテジック・パートナーズエンジニア公式アカウントで発信しています。ご確認ください。

最終更新