【Rails】updateとupdate!の違いと使い分け方


# はじめに
業務でrailsを使っていて、`update`メソッドを使ってユーザー情報を更新する実装をしたので、整理してみました。
`update!`とどっちがいいのでしょうか…?(´・ω・｀)


<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1884151/11625c84-23e7-9f01-3900-a0e3ab5a484e.jpeg" width="300px"><br>
~~※最近はまってるめろぷり~~


# 説明の前にとりまコード比べてみて

あなたがスマホアプリを開発しており、アプリ内の設定画面でユーザー名を変更できるようにすることにしました。
そのために、以下のようなコードを書いたとします。

`update`がこんな感じ
```ruby: update
class User < ApplicationRecord
  validates :username, presence: true
end

class SettingsController < ApplicationController
  def update
    user = current_user
    if user.update(username: params[:new_username])
      # ユーザー名の更新に成功した場合の処理
    else
      # ユーザー名の更新に失敗した場合の処理
    end
  end
end
```

<br>

`update!`がこんな感じ
```ruby: update! 
class User < ApplicationRecord
  validates :username, presence: true
end

class SettingsController < ApplicationController
  def update
    user = current_user
    user.update!(username: params[:new_username])
    # ユーザー名の更新に成功した場合の処理
  rescue ActiveRecord::RecordInvalid => e
    # ユーザー名の更新に失敗した場合の処理
    logger.error("ユーザー名の更新に失敗しました。エラーメッセージ: #{e.record.errors.full_messages}")
  end
end

```


# updateとupdate!の違いとは？

Railsには、`ActiveRecord`オブジェクトを更新するためにupdateとupdate!の2つのメソッドがあります。
これらのメソッドには以下のような違いがあります。

- `updateメソッド` 
    - 更新に成功した場合、更新されたレコードを返す。
    - **更新に失敗した場合、falseを返す。**
    - 更新に失敗した場合、例外を発生させない。


- `update!メソッド`
    - 更新に成功した場合、更新されたレコードを返す。
    - **更新に失敗した場合、例外(ActiveRecord::RecordInvalid)を発生させる。**
    - **バリデーションエラー等、どのような理由で更新に失敗したかを特定できる。**


つまり、updateメソッドは更新に失敗した場合にfalseを返すため、その結果を元に**条件分岐をする必要があります。**
一方、update!メソッドは更新に失敗した場合に例外を発生させるため、**その例外をキャッチしてエラー処理を行う必要があります。**
また、update!メソッドを使用することで、更新に失敗した場合にどのような理由で失敗したかを特定することができます。
これにより、エラーの詳細を把握しやすくなります。

ただし、update!メソッドは例外を発生させるため、実行時にはコストがかかります。
そのため、更新に失敗した場合にすぐに処理を行える場合には、updateメソッドを使用する方が適しています。
また、例外処理を行わなければならない場合には、update!メソッドを使用する方が適しています。

# updateメソッドの使い方と注意点

```ruby: update メソッド
def update_user(params)
  user = User.find(params[:id])
  if user.update(params[:user])
    # 更新が成功した場合の処理
    redirect_to user_path(user)
  else
    # 更新が失敗した場合の処理
    flash[:error] = "ユーザー情報の更新に失敗しました。"
    redirect_to edit_user_path(user)
  end
end
```

このコードでは、updateメソッドを使用して、ユーザー情報の更新を行っています。
更新が成功した場合は、redirect_to user_path(user)でユーザー詳細画面にリダイレクトします。
更新が失敗した場合は、redirect_to edit_user_path(user)で編集画面にリダイレクトし、エラーメッセージを表示します。

しかし、このコードには問題があります。
updateメソッドは更新に失敗した場合にfalseを返すため、どのようなエラーが原因で更新に失敗したかを特定することができません。
そのため、エラーメッセージを適切に表示することができません。

# update!メソッドの使い方と注意点

```ruby: update! メソッド
def update_user(params)
  user = User.find(params[:id])
  if user.update!(params[:user])
    # 更新が成功した場合の処理
    redirect_to user_path(user)
  else
    # ここには到達しない
  end
rescue ActiveRecord::RecordInvalid => e
  # 更新が失敗した場合の処理
  flash[:error] = "ユーザー情報の更新に失敗しました。#{e.message}"
  redirect_to edit_user_path(user)
end

```

このコードでは、update!メソッドを使用してユーザー情報を更新し、例外をキャッチしてエラーメッセージを表示しています。
`update!`メソッドが例外を発生させた場合には、rescue節でActiveRecord::RecordInvalid例外をキャッチし、エラーメッセージを生成してflash[:error]に設定しています。そして、編集画面にリダイレクトします。

このように、update!メソッドを使用することで、更新に失敗した場合に詳細なエラーメッセージを生成することができます。
このメソッドを使用する場合には、更新に失敗した場合の例外処理を行う必要がありますが、エラーの特定やエラーメッセージの生成が簡単になるというメリットがあります。



# どちらを使うべきか？使い分けのポイントとは？

`updateメソッドとupdate!メソッド、どちらを使用するかは、状況に応じて適切に使い分ける必要があります。
以下に、使い分けのポイントをまとめます。

- `updateメソッドを使う場合`
  - 更新に失敗してもエラー処理を行わなくてよい場合に使用する。 
  - 更新に失敗した場合にfalseを返すため、条件分岐で更新に成功したかどうかを判定する必要がある。

- `update!メソッドを使う場合`
  - 更新に失敗した場合にエラー処理を行い、失敗原因を特定する必要がある場合に使用する。
  - 更新に失敗した場合に例外を発生させるため、例外処理が必要となる。


基本的には、エラー処理が必要な場合にはupdate!メソッドを使用することをお勧めします。
updateメソッドでは、更新に失敗した原因を特定することができないため、エラーの原因を特定するために多くの手間がかかります。
一方、update!メソッドは、更新に失敗した原因を特定しやすいため、開発者がエラー処理をスムーズに行うことができます。

ただし、update!メソッドは例外を発生させるため、実行時のコストが高くなるというデメリットもあります。
そのため、更新に失敗してもすぐに処理を行える場合には、updateメソッドを使用する方が適しています。
また、複数のレコードを一度に更新する場合には、update_allメソッドを使用することも検討してください。


# おわりに
調べてみて思うのは、update!でいいんじゃない？ってことです。
まだまだ経験が足りないので分からないことも多いですが、エラーが分かりやすくなるので、update!でいいのではと思いました。
updateのほうがいい！などアドバイスあればコメントほしいです～！！