【Rails】updateメソッドの使い方を徹底解説!

Rails

updateメソッドとは

すでにテーブルに保存されているデータを、新しい情報に更新するメソッドです。

updateの基本的な使い方

updateメソッドの構文

ruby
1
モデルのインスタンス.update(更新データ )

使い方の例

ruby
1
2
@item = Item.find(1)
@item.update( name: "Tシャツ", price: 1800 )

updateメソッドは以下の流れで使用します。
①変数に、更新したいレコードの情報を代入する。
例では、Itemsテーブルのidが1番のデータを代入しています。

②その変数に対してupdateメソッドを使用する。
updateメソッドの引数には、変更後のデータをハッシュ形式で与えます。

実際の書き方をみてみよう

updateメソッドは、通常ストロングパラメータとセットで使用します。

ruby
1
2
3
4
5
6
7
8
9
10
11
12
class ItemsController < ApplicationController

  def update
      @item = Item.find(params[:id])  # ①インスタンス変数にセット
      @item.update(item_params)   # ②updateメソッドの実行
  end

  private
    def item_params
      params.require(:item).permit(:name, :num)
    end
end

①インスタンス変数にセット
ここで、更新したいレコードの情報を@itemという変数に代入しています。
ここで、ユーザーが何番のidのレコードを更新しようとしているのか把握する必要があります。そのため、paramsを使用して取得しています。

paramsについてはこちらで詳しく解説していますのでご参照ください。
paramsについて徹底解説!

②updateメソッドの実行
ここで実際に更新するためのメソッドを実行しています。
updateメソッドの引数には「item_params」と記述しています。これはストロングパラメータを使用して安全にデータを更新したいためです。

詳しく知りたい方はこちらをご確認ください。
ストロングパラメーターについて徹底解説!

ここでは流れだけ確認しておきましょう。
ここで引数に指定している「item_params」はメソッドの名前です。まずこのメソッドが実行され、その結果がupdateメソッドの引数になります。

ruby
1
params.require(:item).permit(:name, :num)

item_paramsメソッドの、上記の部分が実行されると、ユーザーが入力した内容に従ってこのようなハッシュ(のようなもの)ができます。

ruby
1
{ name: "Tシャツ", num: 3 }

この返り値を、updateメソッドの引数に使用しています。 

updateメソッドはコントローラーのどこに書くか

updateメソッドは、コントローラーの7つのアクションのうち、updateの中に記述します。通常editとセットで使用し、editで編集のためのビューの表示を、updateのなかで実際のデータ更新を行います。

アクション名 機能
index リソースの一覧を表示させる
show リソースの詳細を表示させる
new 投稿フォームを表示させる
create リソースを追加させる
edit 更新フォームを表示させる
update リソースを更新させる
destroy リソースを削除する

Railsではこの7つのアクションに従ってメソッドを記述することが、可読性を高める上で重要です。使いわけに自信がない場合は、こちらの記事もご参照ください。

resourcesメソッドを徹底解説!

似ているメソッドとの違いや使い分け

updateメソッドと似ているメソッドがいくつか用意されているので、その使いわけについて解説します。

update_attribute

レコードの、1つのカラムを変更できるメソッドです。updateとは引数の書き方が違い、カラム名と値をカンマで区切って指定します。

ruby
1
@item.update_attribute(:num, 100)

update_attributeの実行時は、バリデーションのチェックがされないため、特別な理由がある場合以外は使用しないことが好ましいでしょう。

update_attributes

update_attributesはupdateのエイリアスメソッド(別名)なので、動作は全く同じです。

upate_all

update_allは、レコードの全ての値を一括で変更できるメソッドです。

ruby
1
Item.update_all( num: 1)

このような記述で、Itemsテーブルの全てのレコードのnumカラムの値を1に変更することができます。今まで見てきたメソッドとは違い、クラスメソッドなのでItemなどのモデルに対して実行します。

また、実行時にバリデーションがかからないため、誤った操作をすると大きな影響が出てしまう可能性があります。使用するときは注意が必要なメソッドです。

update!

updateとupdate!メソッドの違いは、結果の返し方が異なります。
updateの場合、保存の成否をtrueかfalseで返します。それに対してupdate!は保存に失敗したときに例外を返します。

複数のデータ更新を順次行うときに、トランザクションという機能を使うことがあります。その場合はupdate!を使用すると、例外の発生とともにロールバック処理が行われるのでupdateより便利です。

更新がうまくいったときと、そうでないときで処理を分ける方法

バリデーションをかけている時など、更新処理に失敗することがあります。成功か失敗かで処理を分ける方法を解説します。

ruby
1
2
3
4
5
6
7
(省略)
if @item.update(item_params)
  redirect_to @item
else
  render :edit
end
(省略)

このような書き方で、更新できた場合はredirect_toメソッドが、失敗した時はrenderメソッドが呼ばれるように分岐することができます。

if分の条件式が少しわかりにくいので詳しく確認しましょう。

このようにupdateメソッドの返り値を変数resultに代入するとします。

ruby
1
result = @item.update(item_params)

この時、updateメソッドが成功するとresultに「true」が、失敗した時は「false」が入ります。

よって、返り値がtrueであれば条件が成立しますので、redirect_toが実行されます。逆にfalseであればelseの中身であるrenderが実行される、という流れになります。

updateメソッドがうまく実装できないときのデバッグ方法

更新処理がうまくいかない場合の解決手順を解説します。
全てのケースに当てはまるとは限りませんが、大抵の場合原因にたどり着くと思いますので参考にしてください。

基本的なデバッグの考え方

update関連のコードがうまくいかない場合のデバッグの考え方をご紹介します。
pry-railsを使った方法になりますので、使い方が不安な方は先にこちらをご確認ください。

Pryについて徹底解説!

updateがうまくいくためには、以下のコードが正しく動く必要があります。

①ビューから、ユーザーが入力したデータが正しく送信される。
②ストロングパラメータの許可が正しくできている。
③updateメソッドが正しく実行できる。

逆に言えば、エラーが出てしまう場合は上記の3点がうまくいっているのか、順に確認していけばよいということになります。

①ビューからデータが正常に送信されているか確認する

ruby
1
2
3
4
5
6
7
8
9
10
def update

  binding.pry  

  if @item.update(item_params)
    redirect_to @item
  else
    render :edit
  end
end

binding.pryを使ってアプリを一度止めて内容を確認します。
まずはupdateの冒頭で確認するのがよいでしょう。

binding.pryの記述を追加したら、実際にブラウザで更新操作を行います。
「更新」ボタンを押すと動作が止まりますので、ターミナルを確認します。

ビューからのデータなどは、paramsというメソッドで取り出すことができます。

shell
1
2
[1] pry(#<ItemsController>)> params
=> <ActionController::Parameters {"utf8"=>"✓", "_method"=>"patch", "authenticity_token"=>"0SBiFfAqA/ecV9w4+xd3T+K3lBoxDZQiXnUgpgigQnb7HUeelCaMVIMQntTt4DB000pom4vwHfrBXlnvF9nA6A==", "item"=><ActionController::Parameters {"name"=>"abc", "num"=>"2"} permitted: false>, "commit"=>"Update Item", "controller"=>"items", "action"=>"update", "id"=>"1"} permitted: false>

このような表示がされます。情報が少し多いですが、注目すべきは「"item"=>」の直後です。

ruby
1
 {"name"=>"abc", "num"=>"2"} permitted: false

この前半のハッシュの中に、保存すべきデータが全て入っているかを確認します。もしなければ、ビューの記述に不具合がある可能性があるのでチェックしましょう。

②ストロングパラメータの許可がうまくできているか確認する

①で問題がなければ、続いてストロングパラメータの設定が正しいか見てみましょう。

ターミナルで、ストロングパラメータの記述をしているメソッド名(例えばitem_paramsなど)を実行します。

うまくいっていれば、このような表示がされます。
・保存するためのカラムのデータが全てハッシュに含まれていること
・permitted: trueと表示されきちんと許可がされていること
この2点を確認しましょう。

shell
1
{"name"=>"abc", "num"=>"2"} permitted: true

そうなっていない場合は、ストロングパラメータの設定が誤っている可能性がありますので、コードを確認しましょう。

また、ストロングパラメータについては、以下の記事で詳しく解説しています。
ストロングパラメーターについて徹底解説!

③updateメソッドがうまくいっているか確認する

ここまで確認しても原因が特定できない場合は、最後にupdateメソッドの実行結果を確認してみましょう。

確認のために、ターミナルで実際にupdateメソッドを実行します。

shell
1
2
3
4
5
6
[1] pry(#<ItemsController>)> @item.update(item_params)
   (0.3ms)  BEGIN
  ↳ (pry):7
   (0.2ms)  ROLLBACK
  ↳ (pry):7
=> false

updateメソッドに失敗している時は、このようにROLLBACKによってデータベースの更新が取り消されているはずです。

この原因を探るためには、errorsメソッドが活用できます。

shell
1
2
3
4
5
6
7
8
9
10
11
[2] pry(#<ItemsController>)> @item.errors
=> #<ActiveModel::Errors:0x00007fd5d9a32008
 @base=
  #<Item:0x00007fd5db73e818
   id: 1,
   name: "abc",
   num: 200,
   created_at: Mon, 15 Jul 2019 14:23:18 UTC +00:00,
   updated_at: Sun, 28 Jul 2019 09:21:15 UTC +00:00>,
 @details={:num=>[{:error=>:less_than, :value=>200, :count=>5}]},
 @messages={:num=>["must be less than 5"]}>

上記の例で、@itemのupdateに失敗した時は、@itemの中にエラー情報が格納されます。それを取り出すのがerrorsメソッドです。

@messagesを見ると、「:num」に対して「"must be less than 5"」というエラーメッセージが出ていることがわかります。

これは、numカラムに「5未満」というバリデーションの設定をしているにも関わらず、それ以上の数で更新しようとしたことを意味しています。

そのため、5未満の数で更新すればうまくいくはずですし、実際のアプリ開発では少ない数の入力を促すメッセージを表示すべきでしょう。

まとめ

・updateはテーブルのデータを更新するためのメソッドです。

・うまく実装できないときはpryを使って原因を探ってみましょう。