LoginSignup
11
8

More than 3 years have passed since last update.

【Rails DB更新、該当するデータを全て更新するには】

Last updated at Posted at 2019-06-23

はじめに

Ruby on RailsでDBの該当するデータを全て更新したい。初心者なりにやり方をまとめてみます。
今回サンプルで用意したDBはこちら。

User
id| name |age|hobby   |created_at                |updated_at
 1|Mary  |22 |cooking |2019-06-18 00:31:31.224467|2019-06-18 00:31:31.224467
 2|John  |25 |soccer  |2019-06-18 00:35:03.354101|2019-06-21 09:20:15.644253
 3|Alice |25 |swimming|2019-06-18 00:38:13.875116|2019-06-18 00:38:13.875116
 4|Tom   |28 |baseball|2019-06-21 08:39:12.363736|2019-06-21 08:39:12.363736
 5|Nina  |20 |soccer  |2019-06-21 08:39:24.677422|2019-06-21 08:39:24.677422
 6|Mark  |21 |travel  |2019-06-21 08:39:39.254744|2019-06-21 08:39:39.254744

最終的に25歳のUserの趣味を'game'に更新しようと思います。

まずは対象のデータを取得する -find_byかwhereか-

ここでまず気になったのが、find_bywhere、どちらを使ったら良いのだろうか。。。
試しにfind_byを。

User.find_by(age:25)
  User Load (0.3ms)  SELECT  "users".* FROM "users" WHERE "users"."age" = ? LIMIT ?  [["age", 25], ["LIMIT", 1]]
=> #<User id: 2, name: "John", age: 25, hobby: "soccer", created_at: "2019-06-18 00:35:03", updated_at: "2019-06-21 09:47:12">

ん〜、Johnのデータしか取得されていません。。。
Railsドキュメントによると、find_byは検索条件を指定して、最初の1件を取得するとのこと。(http://railsdoc.com/references/find_by)
なるほど。
では、whereで試してみます。

User.where(age:25)
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."age" = ? LIMIT ?  [["age", 25], ["LIMIT", 11]]
=> #<ActiveRecord::Relation [#<User id: 2, name: "John", age: 25, hobby: "soccer", created_at: "2019-06-18 00:35:03", updated_at: "2019-06-21 09:47:12">,
 #<User id: 3, name: "Alice", age: 25, hobby: "swimming", created_at: "2019-06-18 00:38:13", updated_at: "2019-06-21 09:47:48">]>

無事にJohnとAliceのデータを取得できました。whereを使うと該当データを全て取得できるようです!
find_byとは異なり、ActiveRecord::Relationの文字が。こちらは追って詳しく調べたいと思います。

データの更新

こちらはupdateを使えば上手くいきそうな予感がします。

 User.where(age:25).update(hobby:'game')
  User Load (0.3ms)  SELECT "users".* FROM "users" WHERE "users"."age" = ?  [["age", 25]]
   (0.1ms)  begin transaction
  User Update (0.9ms)  UPDATE "users" SET "hobby" = ?, "updated_at" = ? WHERE "users"."id" = ?  [["hobby", "game"], ["updated_at", "2019-06-21 10:10:54.641391"], ["id", 2]]
   (0.8ms)  commit transaction
   (0.0ms)  begin transaction
  User Update (0.3ms)  UPDATE "users" SET "hobby" = ?, "updated_at" = ? WHERE "users"."id" = ?  [["hobby", "game"], ["updated_at", "2019-06-21 10:10:54.644219"], ["id", 3]]
   (0.5ms)  commit transaction
=> [#<User id: 2, name: "John", age: 25, hobby: "game", created_at: "2019-06-18 00:35:03", updated_at: "2019-06-21 10:10:54">,
    #<User id: 3, name: "Alice", age: 25, hobby: "game", created_at: "2019-06-18 00:38:13", updated_at: "2019-06-21 10:10:54">]

更新できました! しかし、これだと一つずつデータを見ていっているので、データ数が多くなると処理が重たくなりそうです…。

もっとガバっと処理できる方法は無いのでしょうか……

Railsドキュメントで調べてみると、update_allというのを発見!
こちらは条件に一致するレコードをすべて更新するそうです。(http://railsdoc.com/references/update)
早速試してみました(DBは元の状態に戻します)。

User.where(age:25).update_all(hobby:'game')
  User Update All (2.7ms)  UPDATE "users" SET "hobby" = 'game' WHERE "users"."age" = ?  [["age", 25]]
=> 2

更新した件数だけ表示されているようです。
DBを確認してみます。

User
id| name |age|hobby   |created_at                |updated_at
1 |Mary  |22 |cooking |2019-06-18 00:31:31.224467|2019-06-18 00:31:31.224467
2 |John  |25 |game    |2019-06-18 00:35:03.354101|2019-06-21 10:14:38.844045
3 |Alice |25 |game    |2019-06-18 00:38:13.875116|2019-06-21 10:15:00.038129
4 |Tom   |28 |baseball|2019-06-21 08:39:12.363736|2019-06-21 08:39:12.363736
5 |Nina  |20 |soccer  |2019-06-21 08:39:24.677422|2019-06-21 08:39:24.677422
6 |Mark  |21 |travel  |2019-06-21 08:39:39.254744|2019-06-21 08:39:39.254744

whereupdate_allの組み合わせで、無事に25歳のUserの趣味を'game'に更新できました!

まとめ

・該当するデータを全て取得したい場合は、whereを使う
・データを一気に更新したい場合は、update_allを使う

update_allはバリデーションが行われないので、バリデーションによる検証が必要であればupdateを使ったほうが良さそうです。(http://railsdoc.com/references/update)

初心者ですので、間違っている点等あればご指摘いただけますと幸いです。

11
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
8