【Rails入門】update_allでレコードをサクッと更新する

Ruby on Rails(以降、Rails)で、レコードを更新する方法はいくつも用意されていることをご存知でしょうか。

今回は、その中からバリデーションやコールバックを実行せずに、レコードをサクッと更新するupdate_allを紹介します。

update_allは、以下のような目的で使えるメソッドです。

・すべてのレコードを漏れなく更新する
・条件に一致したレコードをすべて更新する
・上位3件のレコードのみを更新する
・ランダムに抽出した2件のレコードのみを更新する

この記事では、scaffoldを使ってWebアプリを作成し、update_allの使いかたを具体的に見ていきます。

それでは、はじめましょう。

update_allとは

update_allは、複数のレコードを一括更新するためのメソッドです。

update_allは、以下のように使います。

モデル.update_all(updates)

引数に指定するupdatesには、SQL文のSET部分を表す文字列やハッシュを指定します。

指定方法
文字列User.update_all("'check' = 'false'")
User.update_all("'check' = 'false', 'birth' = '2000-01-01'")
ハッシュUser.update_all(check: false)
User.update_all(check: false, birth: '2000-01-01')

User.update_all("'check' = 'false'")やUser.update_all(check: false)は、Userテーブルのすべてのレコードのcheckをfalseに変更します。

どちらの書きかたでも同じ動作になります。

通常、Active Recordオブジェクトのメソッドを利用して値を更新すると、バリデーションやコールバックが実行されます。

しかし、update_allは、ActiveRecordオブジェクトを経由しない更新方法のため、バリデーションやコールバックが実行されませんので、注意が必要です。

動作を確認するためのWebアプリを作成する

update_allの雰囲気をつかんだところで、update_allの動作を確認するために、Rails 5.1をインストールしてWebアプリを作りましょう。

(1)Railsをインストールします。

私は、以下の記事を参考に、VirtualBoxで作成した仮想パソコンにインストールしたLinux Mintに、Railsの開発環境を作成しました。

基本的には記事の手順に従って操作しますが、app/samurai/sample1ディレクトリを作成する代わりに、app/samurai/update_all-demoディレクトリを作成しました。

Railsを起動して、ブラウザで画面が表示されることを確認したら、いったんRailsを終了してから次に進みます。

初心者でもかんたん!Ruby on Rails の開発環境の構築手順(Mac/Windows 両対応)
更新日 : 2019年8月9日

Linux Mintのインストールについては、以下の記事で詳しく説明しています。

Linux Mint Cinnamonエディションを使ってみよう
更新日 : 2019年5月22日

(2)Gemfileの最終行に以下の内容を追記します。

gem 'hirb'
gem 'hirb-unicode'

Hirbについては、以下の記事で詳しく説明していますので、あわせてご覧ください。

【Rails入門】初心者が知っておくべき3つのgem
更新日 : 2019年8月9日

(3)新しい「端末」を起動して、以下のコマンドを1行ずつ順番に入力します。

cd app/samurai/attributes-demo
bundle install
bin/rails generate scaffold User name:string birth:date check:boolean
bin/rails db:migrate
bin/rails console

(4)以下のコードを1行ずつ順番に入力します。

User.create(name:"山田太郎", birth:"1991-09-22")
User.create(name:"長瀬来", birth:"1991-10-18")
User.create(name:"立川裕美", birth:"1968-06-28")
User.create(name:"前田達郎", birth:"1984-10-12")
User.create(name:"細川修二", birth:"1971-03-24")
User.create(name:"木村拓磨", birth:"1995-05-19")
exit

Userテーブルにデータが入力され、Railsコンソールが終了します。

update_allでレコードを一括更新する

すべてのレコードを漏れなく更新する

最も簡単な例です。

すべてのレコードのcheckをtrueに変更します。

(1)「端末」で以下のコマンドを入力します。

bin/rails console

(2)以下のコードを1行ずつ順番に入力します。

Hirb.enable
User.update_all(check: true)
User.all

実行結果:

  User Load (0.3ms)  SELECT "users".* FROM "users"
+----+----------+------------+-------+-------------------------+-------------------------+
| id | name     | birth      | check | created_at              | updated_at              |
+----+----------+------------+-------+-------------------------+-------------------------+
| 1  | 山田太郎 | 1991-09-22 | true  | 2018-07-24 02:16:01 UTC | 2018-07-24 02:16:01 UTC |
| 2  | 長瀬来   | 1991-10-18 | true  | 2018-07-24 02:16:01 UTC | 2018-07-24 02:16:01 UTC |
| 3  | 立川裕美 | 1968-06-28 | true  | 2018-07-24 02:16:01 UTC | 2018-07-24 02:16:01 UTC |
| 4  | 前田達郎 | 1984-10-12 | true  | 2018-07-24 02:16:01 UTC | 2018-07-24 02:16:01 UTC |
| 5  | 細川修二 | 1971-03-24 | true  | 2018-07-24 02:16:01 UTC | 2018-07-24 02:16:01 UTC |
| 6  | 木村拓磨 | 1995-05-19 | true  | 2018-07-24 02:16:01 UTC | 2018-07-24 02:16:01 UTC |
+----+----------+------------+-------+-------------------------+-------------------------+
6 rows in set

条件に一致したレコードをすべて更新する

40歳未満(birthが40.year.ago以降)のUserに限り、checkをtrueにしてみます。

(1)「端末」で以下のコマンドを入力します。

bin/rails console

(2)以下のコードを1行ずつ順番に入力します。

Hirb.enable
User.update_all(check: false)
User.where(['birth > ?', 40.year.ago]).update_all(check: true)
User.all

実行結果:

  User Load (0.1ms)  SELECT "users".* FROM "users"
+----+----------+------------+-------+-------------------------+-------------------------+
| id | name     | birth      | check | created_at              | updated_at              |
+----+----------+------------+-------+-------------------------+-------------------------+
| 1  | 山田太郎 | 1991-09-22 | true  | 2018-07-24 02:16:01 UTC | 2018-07-24 02:16:01 UTC |
| 2  | 長瀬来   | 1991-10-18 | true  | 2018-07-24 02:16:01 UTC | 2018-07-24 02:16:01 UTC |
| 3  | 立川裕美 | 1968-06-28 | false | 2018-07-24 02:16:01 UTC | 2018-07-24 02:16:01 UTC |
| 4  | 前田達郎 | 1984-10-12 | true  | 2018-07-24 02:16:01 UTC | 2018-07-24 02:16:01 UTC |
| 5  | 細川修二 | 1971-03-24 | false | 2018-07-24 02:16:01 UTC | 2018-07-24 02:16:01 UTC |
| 6  | 木村拓磨 | 1995-05-19 | true  | 2018-07-24 02:16:01 UTC | 2018-07-24 02:16:01 UTC |
+----+----------+------------+-------+-------------------------+-------------------------+
6 rows in set

上位3件のレコードのみを更新する

今度は、上位3位(年長者上位3名)に限り、checkをtrueにする方法です。

(1)「端末」で以下のコマンドを入力します。

bin/rails console

(2)以下のコードを1行ずつ順番に入力します。

Hirb.enable
User.update_all(check: false)
User.order(:birth).limit(3).update_all(check: true)
User.all

実行結果:

  User Load (0.1ms)  SELECT "users".* FROM "users"
+----+----------+------------+-------+-------------------------+-------------------------+
| id | name     | birth      | check | created_at              | updated_at              |
+----+----------+------------+-------+-------------------------+-------------------------+
| 1  | 山田太郎 | 1991-09-22 | false | 2018-07-24 02:16:01 UTC | 2018-07-24 02:16:01 UTC |
| 2  | 長瀬来   | 1991-10-18 | false | 2018-07-24 02:16:01 UTC | 2018-07-24 02:16:01 UTC |
| 3  | 立川裕美 | 1968-06-28 | true  | 2018-07-24 02:16:01 UTC | 2018-07-24 02:16:01 UTC |
| 4  | 前田達郎 | 1984-10-12 | true  | 2018-07-24 02:16:01 UTC | 2018-07-24 02:16:01 UTC |
| 5  | 細川修二 | 1971-03-24 | true  | 2018-07-24 02:16:01 UTC | 2018-07-24 02:16:01 UTC |
| 6  | 木村拓磨 | 1995-05-19 | false | 2018-07-24 02:16:01 UTC | 2018-07-24 02:16:01 UTC |
+----+----------+------------+-------+-------------------------+-------------------------+
6 rows in set

orderlimitを組み合わせて使うと、一見難しそうな更新も簡単に実現できました。

ランダムに抽出した2件のレコードのみを更新する

少し目先を変えて、ランダムに抽出した2件のレコードのみ、checkをtrueにしてみます。

抽選に使うイメージですね。

(1)「端末」で以下のコマンドを入力します。

bin/rails console

(2)以下のコードを1行ずつ順番に入力します。

Hirb.enable
User.update_all(check: false)
User.where('id >= ?', rand(User.first.id..User.last.id)).limit(2).update_all(check: true)
User.all

実行結果:

  User Load (0.1ms)  SELECT "users".* FROM "users"
+----+----------+------------+-------+-------------------------+-------------------------+
| id | name     | birth      | check | created_at              | updated_at              |
+----+----------+------------+-------+-------------------------+-------------------------+
| 1  | 山田太郎 | 1991-09-22 | false | 2018-07-24 02:16:01 UTC | 2018-07-24 02:16:01 UTC |
| 2  | 長瀬来   | 1991-10-18 | false | 2018-07-24 02:16:01 UTC | 2018-07-24 02:16:01 UTC |
| 3  | 立川裕美 | 1968-06-28 | false | 2018-07-24 02:16:01 UTC | 2018-07-24 02:16:01 UTC |
| 4  | 前田達郎 | 1984-10-12 | false | 2018-07-24 02:16:01 UTC | 2018-07-24 02:16:01 UTC |
| 5  | 細川修二 | 1971-03-24 | true  | 2018-07-24 02:16:01 UTC | 2018-07-24 02:16:01 UTC |
| 6  | 木村拓磨 | 1995-05-19 | true  | 2018-07-24 02:16:01 UTC | 2018-07-24 02:16:01 UTC |
+----+----------+------------+-------+-------------------------+-------------------------+
6 rows in set

※毎回、実行結果が異なります。

その他の更新メソッド

初めにも書きましたが、update_allではバリデーションやコールバックが実行されません。

バリデーションやコールバックが必要なら、updateupdate_attributesを使います。

Railsで利用できる、値を更新するメソッドについては、以下の記事で詳しく説明していますので、あわせてご覧ください。

【Rails入門】update_attributesで更新する方法をわかりやすく解説
更新日 : 2019年5月20日

まとめ

今回は、Railsでレコードを更新する方法の一つであるupdate_allの使いかたを紹介しました。

whereorderと組み合わせてupdate_allを使うと、条件に一致したレコードだけ一括して値を変更できました。

それから、update_attributesなどとは異なり、update_allはバリデーションやコールバックが実行されないため、おかしな値に変更しないように十分注意しましょう。

update_allに限らず、こういったフレームワークでは、似たような機能のメソッドとの違いを理解して使用することが大切です。

一つ一つ丁寧に動作を確認しながら使用していきましょう。

それでは!

LINEで送る
Pocket

SEからWebエンジニアへ転職した理由

侍エンジニア塾卒業生の小池さんは、以前は社内SEとして約5年ほど勤務していました。しかし業務内容は社内のヘルプデスク対応など、プログラムを書く仕事は全くなかったそうです。

SEながらプログラムを書けない現状に「将来仕事がなくなるんじゃないか」と不安を感じ、プログラミング学習を決意。

弊社スクールで学習し、無事ベンチャー企業のプログラマーとして転職に成功しました。そんな小池さんの学習法や転職体験談を伺いましたので、是非ご覧ください。

「プログラミングができないSEは仕事がなくなる」不安を感じたSEが未経験から転職成功するまで
更新日 : 2019年10月7日

書いた人

侍テック編集部

侍テック編集部

おすすめコンテンツ

あなたにぴったりなプログラミング学習プランを無料で診断!

プログラミング学習の効率を劇的に上げる学習メソッドを解説