rails/activerecord/CHANGELOG.md @ 300d080ada31ac297264e6abba6ca16cd2db5925
を読んでみたので誤訳 & わからない部分は後で調べ直すためのメモ。
find_or_create_by, find_or_create_by!, find_or_initializeが追加されている。
これらのメソッドはfirst_or_create系のメソッドと似ているが、レコードが作られるときの振る舞いは少し異なっている。
User.Where(firstname: 'Hoge').first_or_create
はスコープのコンテキストで実行されるcreateコールバックを伴って
User.Where(firstname: 'Hoge').create
を実行する。これは、コールバック内で実行するクエリに影響を及ぼす。
(Whereの結果がcreateに影響するということでいいのかな?)
User.find_or_create(firstname: 'Hoge')
は
User.create(firstname: 'Hoge')
を実行する。これは明らかにコールバック内のクエリのスコープに影響を与えない。(うーん、確かにWhereが消えたのでWhereの結果がcreateのクエリを汚すことはないか。ただ、これだと、find_or_create_byのfindの意味合いがよくわからないとおもうのだが・・・。あとで調べ直す。)
find_or_create_byを利用したほうは読みやすく、素直だ。
もし、レコード生成時に追加で必要な属性があるなら、以下の方法のうちどちらかを採用すればいい。
User.create_with(active:true).find_or_create_by(firstname: 'Hoge')
User.find_or_create(firstname: 'Hoge'){|u| u.active = true}
first_or_create系のメソッドはfind_or_createのAPIを支持して、nodoc'edとした。first_or_create系のメソッドはそのうちdeprecatedとなるかもしれないが、これらの実装は少なく、たくさんのうっとうしいdeprecation warningをユーザに出す価値は多分ないでしょう。
("これらの実装は小さく"の部分がわからんなぁ。後で調べ直す。)