###ユーザーオブジェクトを検索する
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