0
0

More than 1 year has passed since last update.

railsチュートリアル第6章 ユーザーオブジェクトを検索する

Posted at

ユーザーオブジェクトを検索する

Active Recordには、オブジェクトを検索するための方法がいくつもあります
過去に作成した最初のユーザーを探してみましょう。
3番目のユーザー(foo)が削除されていることを確認しましょう。まずは存在するユーザーから探してみましょう。

>> User.find(1)
  User Load (0.2ms)  SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> #<User id: 1, name: "Michael Hartl", email: "michael@example.com", created_at: "2021-09-23 05:29:52", updated_at: "2021-09-23 05:29:52">
>> User.create(name: "A Nother", email: "another@example.org")
   (0.1ms)  begin transaction
  User Create (2.0ms)  INSERT INTO "users" ("name", "email", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["name", "A Nother"], ["email", "another@example.org"], ["created_at", "2021-09-23 05:30:33.448620"], ["updated_at", "2021-09-23 05:30:33.448620"]]
   (6.6ms)  commit transaction
=> #<User id: 2, name: "A Nother", email: "another@example.org", created_at: "2021-09-23 05:30:33", updated_at: "2021-09-23 05:30:33">
>> User.find(2)
  User Load (0.2ms)  SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
=> #<User id: 2, name: "A Nother", email: "another@example.org", created_at: "2021-09-23 05:30:33", updated_at: "2021-09-23 05:30:33">
>> User.find(3)
  User Load (0.1ms)  SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 3], ["LIMIT", 1]]
Traceback (most recent call last):
        1: from (irb):8
ActiveRecord::RecordNotFound (Couldn't find User with 'id'=3)

3番目のユーザーを削除したので、Active Recordはこのユーザーをデータベースの中から見つけることができませんでした。代わりに、findメソッドは例外(exception)を発生します。

Active Recordのidによって、findを読み込んだときにActiveRecord::RecordNotFoundという例外が発生しました。

一般的なfindメソッド以外に、Active Recordには特定の属性でユーザーを検索する方法もあります

>> User.find_by(email: "michael@example.com")                              
  User Load (0.2ms)  SELECT "users".* FROM "users" WHERE "users"."email" = ? LIMIT ?  [["email", "michael@example.com"], ["LIMIT", 1]]
=> #<User id: 1, name: "Michael Hartl", email: "michael@example.com", created_at: "2021-09-23 05:29:52", updated_at: "2021-09-23 05:29:52">

メールアドレスをユーザー名として使ってきたので、このようなfind関連メソッドは、ユーザーをサイトにログインさせる方法を学ぶときに役に立ちます。
ユーザー数が膨大になるとfind_byでは検索効率が低下するのではないかと心配する方もいるかもしれませんが、あせる必要はありません。この問題およびデータベースのインデックスを使った解決策がある。

>> User.first
  User Load (0.2ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> #<User id: 1, name: "Michael Hartl", email: "michael@example.com", created_at: "2021-09-23 05:29:52", updated_at: "2021-09-23 05:29:52">
>> User.all
  User Load (0.2ms)  SELECT "users".* FROM "users" LIMIT ?  [["LIMIT", 11]]
=> #<ActiveRecord::Relation [#<User id: 1, name: "Michael Hartl", email: "michael@example.com", created_at: "2021-09-23 05:29:52", updated_at: "2021-09-23 05:29:52">, #<User id: 2, name: "A Nother", email: "another@example.org", created_at: "2021-09-23 05:30:33", updated_at: "2021-09-23 05:30:33">, #<User id: 3, name: "A Nother", email: "another@example.org", created_at: "2021-09-23 05:36:55", updated_at: "2021-09-23 05:36:55">, #<User id: 4, name: "Michael Hartl", email: "michael@example.com", created_at: "2021-09-23 05:37:09", updated_at: "2021-09-23 05:37:09">]>

演習

1.nameを使ってユーザーオブジェクトを検索してみてください。また、find_by_nameメソッドが使えることも確認してみてください。

>> User.find_by(name: "Michael Hartl")
  User Load (0.2ms)  SELECT "users".* FROM "users" WHERE "users"."name" = ? LIMIT ?  [["name", "Michael Hartl"], ["LIMIT", 1]]
=> #<User id: 1, name: "Michael Hartl", email: "michael@example.com", created_at: "2021-09-23 05:29:52", updated_at: "2021-09-23 05:29:52">

>> User.find_by_name("Michael Hartl")                                     
   (0.1ms)  begin transaction
  User Load (0.8ms)  SELECT "users".* FROM "users" WHERE "users"."name" = ? LIMIT ?  [["name", "Michael Hartl"], ["LIMIT", 1]]
=> #<User id: 1, name: "Michael Hartl", email: "michael@example.com", created_at: "2021-09-23 05:29:52", updated_at: "2021-09-23 05:29:52">

2.実用的な目的のため、User.allはまるで配列のように扱うことができますが、実際には配列ではありません。User.allで生成されるオブジェクトを調べ、ArrayクラスではなくUser::ActiveRecord_Relationクラスであることを確認してみてください。

>> User.all
  User Load (0.2ms)  SELECT "users".* FROM "users" LIMIT ?  [["LIMIT", 11]]
=> #<ActiveRecord::Relation [#<User id: 1, name: "Michael Hartl", email: "michael@example.com", created_at: "2021-09-23 05:29:52", updated_at: "2021-09-23 05:29:52">, #<User id: 2, name: "A Nother", email: "another@example.org", created_at: "2021-09-23 05:30:33", updated_at: "2021-09-23 05:30:33">]>
>> User.all.class
=> User::ActiveRecord_Relation

3.User.allに対してlengthメソッドを呼び出すと、その長さを求められることを確認してみてください。
Rubyの性質として、そのクラスを詳しく知らなくてもなんとなくオブジェクトをどう扱えば良いかわかる、という性質があります。
これをダックタイピング(duck typing)と呼び、
よく次のような格言で言い表されています「もしアヒルのような容姿で、アヒルのように鳴くのであれば、それはもうアヒルだろう」。

(訳注: そういえばRubyKaigi 2016の基調講演で、Ruby作者のMatzがダックタイピングについて説明していました。2〜3分の短くて分かりやすい説明なので、ぜひ視聴してみてください!)

>> User.all.length
  User Load (0.2ms)  SELECT "users".* FROM "users"
=> 2
0
0
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
0
0