first_or_initializeとfind_or_initialize_by


この2つのメソッドは同じような用途で使えますが、どのような使い分けをすればいいのかをまとめてみました。

find_or_initialize_by

# File activerecord/lib/active_record/relation.rb, line 222
def find_or_initialize_by(attributes, &block)
  find_by(attributes) || new(attributes, &block)
end

find_bynewの引数に同じattributesが渡される。
なので、下記のようなJOINしたテーブルを検索条件に含めるとActiveRecord::AssociationTypeMismatchの例外が発生する。

A.joins(:bs).find_or_initialize_by(bs: {id: 1})

first_or_initialize


# File activerecord/lib/active_record/relation.rb, line 161
def first_or_initialize(attributes = nil, &block)
  first || new(attributes, &block)
end

firstがない場合、first_or_initailizeの第一引数でオブジェクトを初期化するので、下記のように検索した条件とは別にAttributeで初期化することができる。

A.where(name: "foo").first_or_initialize(name: "bar")

引数を省略すると、もちらんAttributeはなにも設定されないまま初期化される。

まとめ

  • joinをして、検索条件にjoinしたテーブルが含んでいる場合はfirst_or_initialize
  • 検索条件と初期化したいオブジェクトのAttributeと違う場合はfirst_or_initialize、同じ場合はfind_or_initialize_by

参考リンク