【Rails】saveとsave!について

先日うちの開発メンバーから新人さんに共有があったんですが、
saveとsave!の振る舞いの違いなどについてまとめておきます。


当然のことながら、ActiveRecordでは、モデルオブジェクトの値を変更、保存、削除することができ、対応するレコードの内容を更新することができます。属性の値を変更、保存するメソッドはたくさんありますが、自分が使うところで以下一例です。

save、save!、create、create!、update、update_all、update_attribute、update_attributes、update_attributes!、destroy、destroy_all、delete、delete_all

ActiveRecord::Baseを継承したモデルオブジェクトの属性の変更について、ぽちぽちまとめてみようかなとは思いますが、とりあえず、話に上がったsaveとsave!について(´・ω・`)

まず、saveとsave!の違いは、保存出来なかった場合の振る舞いにあります。

・saveメソッドは、保存できない場合falseを返します。
・save!メソッドは、保存できない場合例外ActiveRecord::RecordInvalidが発生します。

ちなみに、どちらもバリデーションの実行をするので、バリデーションを行わない場合は、
save(:validate => false)またはsave!(:validate => false)でスキップできます。

saveとsave!は一見同じようには見えますが、falseを返すのか例外を発生させるのかの違いから、
それぞれのよく使われる利用シーンは以下のような感じです(´・ω・`)


◯DBに保存できたかどうかによって処理を分岐したい場合
大概saveが使われます。
true、falseが戻ってきてくれればさえ良いので。

@hoge = Hoge.new(:name => "piyo")
if @hoge.save
  p "ゆっくりしていってね!"
else
  p "ぬるぽ"
end

例えばこれをあえて、

@hoge = Hoge.new(:name => "piyo")
begin
  @hoge.save!
  p "ゆっくりしていってね!"
rescue
  p "ぬるぽ"
end

と書くと、処理が増えてきた時に追いかけきれなくなります(´・ω・`;)
ただ以下の場合は別です。


トランザクション中にデータを保存したい場合
こちらは大概save!が使われます。
transactionメソッドは例外が発生した場合にロールバックするので、保存に失敗したら例外を発生させなくてはいけません。

@hoge = Hoge.new(:name => "piyo")
begin
  Hoge.transaction do
    @hoge.save!
  end
  p "ゆっくりしていってね!"
rescue
  p "ぬるぽ"
end


◯コンソールからデータを操作、更新する
これはもう別にsaveでもsave!でもどっちでもかまいませんw
お好きなほうでw


あとでまとめようかなとは思いますけど、create!、update_attributes!も同様です。