Railsの6章ではモデルの扱い方を覚えていきます。
- 1. 6.1.1 データベースの移行
- 2. 6.1.2 modelファイル
- 3. 6.1.3 ユーザーオブジェクトを作成する
- 4. 6.1.4 ユーザーオブジェクトを検索する
- 4.1. 1.nameを使ってユーザーオブジェクトを検索してみてください。また、 find_by_nameメソッドが使えることも確認してみてください (古いRailsアプリケーションでは、古いタイプのfind_byをよく見かけることでしょう)。
- 4.2. 2.実用的な目的のため、User.allはまるで配列のように扱うことができますが、実際には配列ではありません。User.allで生成されるオブジェクトを調べ、ArrayクラスではなくUser::ActiveRecord_Relationクラスであることを確認してみてください。
- 4.3. 3.User.allに対してlengthメソッドを呼び出すと、その長さを求められることを確認してみてください (4.2.3)。Rubyの性質として、そのクラスを詳しく知らなくてもなんとなくオブジェクトをどう扱えば良いかわかる、という性質があります。これをダックタイピング (duck typing) と呼び、よく次のような格言で言い表されています「もしアヒルのような容姿で、アヒルのように鳴くのであれば、それはもうアヒルだろう」。(訳注: そういえばRubyKaigi 2016の基調講演で、Ruby作者のMatzがダックタイピングについて説明していました。2〜3分の短くて分かりやすい説明なので、ぜひ視聴してみてください!)
- 5. 6.1.5 ユーザーオブジェクトを更新する
- 6. 6.2.1 有効性を検証する
- 7. 6.2.2 存在性を検証する
- 8. 6.2.3 長さを検証する
- 9. 6.2.4 フォーマットを検証する
- 9.1. 1.リスト 6.18にある有効なメールアドレスのリストと、リスト 6.19にある無効なメールアドレスのリストをRubularのYour test string:に転記してみてください。その後、リスト 6.21の正規表現をYour regular expression:に転記して、有効なメールアドレスのみがすべてマッチし、無効なメールアドレスはすべてマッチしないことを確認してみましょう
- 9.2. 2.先ほど触れたように、リスト 6.21のメールアドレスチェックする正規表現は、foo@bar..comのようにドットが連続した無効なメールアドレスを許容してしまいます。まずは、このメールアドレスをリスト 6.19の無効なメールアドレスリストに追加し、これによってテストが失敗することを確認してください。次に、リスト 6.23で示した、少し複雑な正規表現を使ってこのテストがパスすることを確認してください。
- 9.3. 3.foo@bar..comをRubularのメールアドレスのリストに追加し、リスト 6.23の正規表現をRubularで使ってみてください。有効なメールアドレスのみがすべてマッチし、無効なメールアドレスはすべてマッチしないことを確認してみましょう。
- 10. 6.2.5 一意性を検証する
- 10.1. 1.リスト 6.33を参考に、メールアドレスを小文字にするテストをリスト 6.32に追加してみましょう。ちなみに追加するテストコードでは、データベースの値に合わせて更新するreloadメソッドと、値が一致しているかどうか確認するassert_equalメソッドを使っています。リスト 6.33のテストがうまく動いているか確認するためにも、before_saveの行をコメントアウトして redになることを、また、コメントアウトを解除すると greenになることを確認してみましょう。
- 10.2. 2.テストスイートの実行結果を確認しながら、before_saveコールバックをemail.downcase!に書き換えてみましょう。ヒント: メソッドの末尾に!を付け足すことにより、email属性を直接変更できるようになります (リスト 6.34)。
- 11. 6.3.2 ユーザーがセキュアなパスワードを持っている
- 12. 6.3.3 パスワードの最小文字数
- 13. 6.3.4 ユーザーの作成と認証
6.1.1 データベースの移行
1.Railsはdb/ディレクトリの中にあるschema.rbというファイルを使っています。これはデータベースの構造 (スキーマ (schema) と呼びます) を追跡するために使われます。さて、あなたの環境にあるdb/schema.rbの内容を調べ、その内容とマイグレーションファイル (リスト 6.2) の内容を比べてみてください。
解答
vimで2つのファイルを縦に並べてみました。
:sp ファイル名でできますよ。
ctrl+Wを2回でカーソル移動できます。
:closeで1画面閉じることができます。
migrateファイルの中身が反映されていますねぇ。
この問題はこれでOK。
これはdb:migrateによってできたものなのかがわからないですね。
次の問題にいきましょう。
2.ほぼすべてのマイグレーションは、元に戻すことが可能です (少なくとも本チュートリアルにおいてはすべてのマイグレーションを元に戻すことができます)。元に戻すことを「ロールバック (rollback)と呼び、Railsではdb:rollbackというコマンドで実現できます。
$ rails db:rollback
上のコマンドを実行後、db/schema.rbの内容を調べてみて、ロールバックが成功したかどうか確認してみてください (コラム 3.1ではマイグレーションに関する他のテクニックもまとめているので、参考にしてみてください)。上のコマンドでは、データベースからusersテーブルを削除するためにdrop_tableコマンドを内部で呼び出しています。これがうまくいくのは、drop_tableとcreate_tableがそれぞれ対応していることをchangeメソッドが知っているからです。この対応関係を知っているため、ロールバック用の逆方向のマイグレーションを簡単に実現することができるのです。なお、あるカラムを削除するような不可逆なマイグレーションの場合は、changeメソッドの代わりに、upとdownのメソッドを別々に定義する必要があります。詳細については、Railsガイドの「Active Record マイグレーション」を参照してください。
解答
rails db:rollbackを実行したことにより
drop_tableコマンドが発行されたことを確認できます。
$ rails db:rollback == 20180703045437 CreateUsers: reverting ====================================== -- drop_table(:users) -> 0.0028s == 20180703045437 CreateUsers: reverted (0.0075s) =============================
なぜかキャプチャ使っているのですが、
schema.rbの中身も変わっていることがわかります。
3.もう一度rails db:migrateコマンドを実行し、db/schema.rbの内容が元に戻ったことを確認してください。
解答
rails db:migrateコマンドを実行後、schema.rbを見てみます。
$ rails db:migrate == 20180703045437 CreateUsers: migrating ====================================== -- create_table(:users) -> 0.0043s == 20180703045437 CreateUsers: migrated (0.0044s) =============================
元に戻っていますね。素晴らしい。
6.1.2 modelファイル
1.Railsコンソールを開き、User.newでUserクラスのオブジェクトが生成されること、そしてそのオブジェクトがApplicationRecordを継承していることを確認してみてください (ヒント: 4.4.4で紹介したテクニックを使ってみてください)。
解答
次問にまとめます。
2.同様にして、ApplicationRecordがActiveRecord::Baseを継承していることについて確認してみてください。
解答
superclassを繋げていけば良かったですよね。
# Userクラスが作れることを確認 irb(main):004:0> user = User.new => #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil> irb(main):005:0> user.class => User(id: integer, name: string, email: string, created_at: datetime, updated_at: datetime) # UserクラスがApplicationRecordを継承していることの確認(ここまで問1) irb(main):006:0> user.class.superclass => ApplicationRecord(abstract) # ApplicationRecordがActiveRecord::Baseを継承していることの確認(問2) irb(main):007:0> user.class.superclass.superclass => ActiveRecord::Base
6.1.3 ユーザーオブジェクトを作成する
1.user.nameとuser.emailが、どちらもStringクラスのインスタンスであることを確認してみてください。
解答
以下問にまとめます。
2.created_atとupdated_atは、どのクラスのインスタンスでしょうか?
解答
適当にユーザー作ってからclassで炙り出していきます。
irb(main):008:0> user.save (0.1ms) SAVEPOINT active_record_1 SQL (2.8ms) INSERT INTO "users" ("name", "email", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["name", "AAA"], ["email", "AAA"], ["created_at", "2018-07-03 05:48:49.578233"], ["updated_at", "2018-07-03 05:48:49.578233"]] (0.1ms) RELEASE SAVEPOINT active_record_1 => true irb(main):009:0> user.name.class => String irb(main):010:0> user.email.class => String irb(main):011:0> user.created_at.class => ActiveSupport::TimeWithZone irb(main):013:0> user.updated_at.class => ActiveSupport::TimeWithZone
user.nameとuser.emailはStringクラスのインスタンスであることが分かります。(問1)
created_atとupdated_atはActiveSupport::TimeWithZoneクラスのインスタンスであることが分かります。(問2)
6.1.4 ユーザーオブジェクトを検索する
1.nameを使ってユーザーオブジェクトを検索してみてください。また、 find_by_nameメソッドが使えることも確認してみてください (古いRailsアプリケーションでは、古いタイプのfind_byをよく見かけることでしょう)。
解答
サクッと”AAA”という名前のユーザーを検索してみました。
irb(main):034:0> User.find_by_name("AAA") User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."name" = ? LIMIT ? [["name", "AAA"], ["LIMIT", 1]] => #<User id: 1, name: "AAA", email: "AAA", created_at: "2018-07-03 05:48:49", updated_at: "2018-07-03 05:48:49">
find_by_emailとかもやってみたのですが、同様にできたので、
find_by(カラム: 検索ワード) = find_by_カラム(検索ワード)
が成り立ちますね。
2.実用的な目的のため、User.allはまるで配列のように扱うことができますが、実際には配列ではありません。User.allで生成されるオブジェクトを調べ、ArrayクラスではなくUser::ActiveRecord_Relationクラスであることを確認してみてください。
解答
Users.allで生成されるオブジェクトをusersに格納して、
クラスを確認しています。
User::ActiveRecord_Relationが表示されればOKです。
irb(main):037:0> users = User.all User Load (0.1ms) SELECT "users".* FROM "users" LIMIT ? [["LIMIT", 11]] => #<ActiveRecord::Relation [#<User id: 1, name: "AAA", email: "AAA", created_at: "2018-07-03 05:48:49", updated_at: "2018-07-03 05:48:49">, #<User id: 2, name: "BBB", email: "BBB", created_at: "2018-07-03 05:55:15", updated_at: "2018-07-03 05:56:21">, #<User id: 3, name: "CCC", email: "CCC", created_at: "2018-07-03 05:55:52", updated_at: "2018-07-03 05:55:52">]> irb(main):038:0> users.class => User::ActiveRecord_Relation
3.User.allに対してlengthメソッドを呼び出すと、その長さを求められることを確認してみてください (4.2.3)。Rubyの性質として、そのクラスを詳しく知らなくてもなんとなくオブジェクトをどう扱えば良いかわかる、という性質があります。これをダックタイピング (duck typing) と呼び、よく次のような格言で言い表されています「もしアヒルのような容姿で、アヒルのように鳴くのであれば、それはもうアヒルだろう」。(訳注: そういえばRubyKaigi 2016の基調講演で、Ruby作者のMatzがダックタイピングについて説明していました。2〜3分の短くて分かりやすい説明なので、ぜひ視聴してみてください!)
解答
私は適当に3ユーザー作っていたので、 User.all.length=3となります。
irb(main):040:0> User.all.length User Load (0.2ms) SELECT "users".* FROM "users" => 3
6.1.5 ユーザーオブジェクトを更新する
1.userオブジェクトへの代入を使ってname属性を使って更新し、saveで保存してみてください。
解答
問3にまとめます。
2.今度はupdate_attributesを使って、email属性を更新および保存してみてください。
解答
問3にまとめます。
3.同様にして、マジックカラムであるcreated_atも直接更新できることを確認してみてください。ヒント: 更新するときは「1.year.ago」を使うと便利です。これはRails流の時間指定の1つで、現在の時刻から1年前の時間を算出してくれます。
解答
これもまとめていきましょう
名前が”AAA”というユーザーを作っていたので、
それを”ABC”に更新(問1)
メールアドレスを”AAA@email.com”(問2)
created_atを1年前に改ざんし、(問3)
データが変わったことを確認していきましょう。
irb(main):041:0> user = User.find_by_name("AAA") User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."name" = ? LIMIT ? [["name", "AAA"], ["LIMIT", 1]] => #<User id: 1, name: "AAA", email: "AAA", created_at: "2018-07-03 05:48:49", updated_at: "2018-07-03 05:48:49"> irb(main):042:0> user.name="ABC" => "ABC" irb(main):043:0> user.save (0.1ms) SAVEPOINT active_record_1 SQL (0.2ms) UPDATE "users" SET "name" = ?, "updated_at" = ? WHERE "users"."id" = ? [["name", "ABC"], ["updated_at", "2018-07-03 06:11:40.077938"], ["id", 1]] (0.1ms) RELEASE SAVEPOINT active_record_1 => true irb(main):044:0> user.update_attribute(:email,"AAA@email.com") (0.2ms) SAVEPOINT active_record_1 SQL (0.2ms) UPDATE "users" SET "email" = ?, "updated_at" = ? WHERE "users"."id" = ? [["email", "AAA@email.com"], ["updated_at", "2018-07-03 06:12:42.721509"], ["id", 1]] (0.1ms) RELEASE SAVEPOINT active_record_1 => true irb(main):045:0> user.save (0.1ms) SAVEPOINT active_record_1 (0.1ms) RELEASE SAVEPOINT active_record_1 => true irb(main):046:0> user.update_attribute(:created_at, 1.year.ago) (1.8ms) SAVEPOINT active_record_1 SQL (0.2ms) UPDATE "users" SET "created_at" = ?, "updated_at" = ? WHERE "users"."id" = ? [["created_at", "2017-07-03 06:13:20.951064"], ["updated_at", "2018-07-03 06:13:20.955615"], ["id", 1]] (0.1ms) RELEASE SAVEPOINT active_record_1 => true irb(main):047:0> user.save (0.1ms) SAVEPOINT active_record_1 (0.1ms) RELEASE SAVEPOINT active_record_1 => true irb(main):049:0> User.find_by_name("ABC") User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."name" = ? LIMIT ? [["name", "ABC"], ["LIMIT", 1]] => #<User id: 1, name: "ABC", email: "AAA@email.com", created_at: "2017-07-03 06:13:20", updated_at: "2018-07-03 06:13:20">
問1はuser.nameを使って代入しています。
問2,問3はuser.update_attribute()を使っています。
最後データをfindで検索し、データがきちんと更新されていることを確認します。
正しく更新されていればOKです。
6.2.1 有効性を検証する
1.コンソールから、新しく生成したuserオブジェクトが有効 (valid) であることを確認してみましょう。
解答
問2にまとめます。
2.6.1.3で生成したuserオブジェクトも有効であるかどうか、確認してみましょう。</h3
解答
「オブジェクトが有効である」とはuser.valid?の結果trueが返ってくることですね。
irb(main):001:0> user = User.new => #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil> irb(main):002:0> user.valid? => true irb(main):003:0> user = User.new(name: "Michael Hartl", email: "mhartl@example.com") => #<User id: nil, name: "Michael Hartl", email: "mhartl@example.com", created_at: nil, updated_at: nil> irb(main):004:0> user.valid? => true
最初にUser.newした状態でもtrueが返ります。(問1)
6.1.3で作成したユーザーと同じデータを入れ込み、もう一度user.valid?してももちろん有効です。(問2)
バリデーションが全く設定されていないから今は何してもtrueになります。
この次からバリデーションを扱います。
6.2.2 存在性を検証する
1.新しいユーザーuを作成し、作成した時点では有効ではない (invalid) ことを確認してください。なぜ有効ではないのでしょうか? エラーメッセージを確認してみましょう。
解答
valid?でfalseになることと、invalid?でtrueになること。
両方試してみました。
irb(main):001:0> u = User.new => #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil> irb(main):002:0> u.valid? => false irb(main):003:0> u.invalid? => true irb(main):007:0> u.errors.messages => {:name=>["can't be blank"], :email=>["can't be blank"]}
2.u.errors.messagesを実行すると、ハッシュ形式でエラーが取得できることを確認してください。emailに関するエラー情報だけを取得したい場合、どうやって取得すれば良いでしょうか?
解答
エラーがハッシュになっているのは問1で確認済みですね。
ハッシュなので、キーを指定してあげれば目的の情報のみ取得できますね。
以下のようになります。
irb(main):008:0> u.errors.messages[:email] => ["can't be blank"]
6.2.3 長さを検証する
1.長すぎるnameとemail属性を持ったuserオブジェクトを生成し、有効でないことを確認してみましょう。
解答
最大文字数はnameは50文字、emailは255文字なので、
それを超える文字数で確かめてみれば良いです。
irb(main):001:0> user = User.new => #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil> irb(main):002:0> user.name = "a" * 100 => "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" irb(main):003:0> user.email = "e" * 300 => "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" irb(main):004:0> user.valid? => false
どんなエラーメッセージが出ているかは次問題
2.長さに関するバリデーションが失敗した時、どんなエラーメッセージが生成されるでしょうか? 確認してみてください。
解答
実際にエラーメッセージを表示してみればOKです。
irb(main):005:0> user.errors.messages => {:name=>["is too long (maximum is 50 characters)"], :email=>["is too long (maximum is 255 characters)"]}
6.2.4 フォーマットを検証する
1.リスト 6.18にある有効なメールアドレスのリストと、リスト 6.19にある無効なメールアドレスのリストをRubularのYour test string:に転記してみてください。その後、リスト 6.21の正規表現をYour regular expression:に転記して、有効なメールアドレスのみがすべてマッチし、無効なメールアドレスはすべてマッチしないことを確認してみましょう
解答
以下のようにすればOKです。
2.先ほど触れたように、リスト 6.21のメールアドレスチェックする正規表現は、foo@bar..comのようにドットが連続した無効なメールアドレスを許容してしまいます。まずは、このメールアドレスをリスト 6.19の無効なメールアドレスリストに追加し、これによってテストが失敗することを確認してください。次に、リスト 6.23で示した、少し複雑な正規表現を使ってこのテストがパスすることを確認してください。
解答
foo@bar..comをリストに追加します。
test "email validation should reject invalid addresses" do invalid_addresses = %w[user@example,com user_at_foo.org user.name@example. foo@bar_baz.com foo@bar+baz.com foo@bar..com] invalid_addresses.each do |invalid_address| @user.email = invalid_address assert_not @user.valid?,"#{invalid_address.inspect} should be invalid" end end
テストに失敗します。
$rails test:models (中略) Finished in 0.075274s, 92.9931 runs/s, 212.5558 assertions/s. 7 runs, 16 assertions, 1 failures, 0 errors, 0 skips
class User < ApplicationRecord validates :name,presence: true,length: {maximum:50} #VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i validates :email,presence: true,length: {maximum:255}, format: { with: VALID_EMAIL_REGEX } end
これでテストが通ります。
$rails test:models (中略) Finished in 0.098899s, 70.7792 runs/s, 161.7811 assertions/s. 7 runs, 16 assertions, 0 failures, 0 errors, 0 skips
※(補足)
ちなむと
旧正規表現(/\A[\w+-.]+@[a-z\d-.]+.[a-z]+\z/i)は
(英数字-.)@(半角英小文字半角数字.).(半角英小文字)
新正規表現(/\A[\w+-.]+@[a-z\d-]+(.[a-z\d-]+)*.[a-z]+\z/i)
(英数字-.)@(半角英小文字半角数字)(.半角英小文字半角数字-(ここはなくても良い))(.半角英小文字)
日本語で表そうとすると難しいですね…。
「*」は0回以上の繰り返しですよ
3.foo@bar..comをRubularのメールアドレスのリストに追加し、リスト 6.23の正規表現をRubularで使ってみてください。有効なメールアドレスのみがすべてマッチし、無効なメールアドレスはすべてマッチしないことを確認してみましょう。
解答
以下のようにしてください
6.2.5 一意性を検証する
1.リスト 6.33を参考に、メールアドレスを小文字にするテストをリスト 6.32に追加してみましょう。ちなみに追加するテストコードでは、データベースの値に合わせて更新するreloadメソッドと、値が一致しているかどうか確認するassert_equalメソッドを使っています。リスト 6.33のテストがうまく動いているか確認するためにも、before_saveの行をコメントアウトして redになることを、また、コメントアウトを解除すると greenになることを確認してみましょう。
解答
リスト6.33の通り作ってみます。
test "email addresses should be saved as lower-case" do mixed_case_email = "Foo@ExAMPle.CoM" @user.email = mixed_case_email @user.save assert_equal mixed_case_email.downcase, @user.reload.email end
before_saveの行をコメントアウトしてからテストを実行します。
REDになります。
$rails test:models (中略) Failure: UserTest#test_email_addresses_should_be_saved_as_lower-case [/home/vagrant/tutorial2/sample_app/test/models/user_test.rb:62]: Expected: "foo@example.com" Actual: "Foo@ExAMPle.CoM" bin/rails test test/models/user_test.rb:58 .. 9/8: [================================= ] 88% Time: 00:00:00, ETA: 00:00:. 9/9: [=====================================] 100% Time: 00:00:00, Time: 00:00:00 . Finished in 0.10175s 9 tests, 18 assertions, 1 failures, 0 errors, 0 skips
コメントを外すとGREENになります。
2.テストスイートの実行結果を確認しながら、before_saveコールバックをemail.downcase!に書き換えてみましょう。ヒント: メソッドの末尾に!を付け足すことにより、email属性を直接変更できるようになります (リスト 6.34)。
解答
破壊的メソッドを使うやつですね。動作は変わらないのでテストは通ります。
class User < ApplicationRecord before_save { email.downcase! } validates :name, presence: true, length: { maximum: 50 } VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i validates :email, presence: true, length: { maximum: 255 }, format: { with: VALID_EMAIL_REGEX }, uniqueness: { case_sensitive: false } end
$rails test:models (中略) Finished in 0.114386s, 78.6812 runs/s, 157.3623 assertions/s. 9 runs, 18 assertions, 0 failures, 0 errors, 0 skips
6.3.2 ユーザーがセキュアなパスワードを持っている
1.この時点では、userオブジェクトに有効な名前とメールアドレスを与えても、valid?で失敗してしまうことを確認してみてください。
解答
コンソールで確認していきましょう。
適当にname=user1,email=user1@email.comとしました。
irb(main):001:0> user = User.new => #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil, password_digest: nil> irb(main):002:0> user.name = "user1" => "user1" irb(main):003:0> user.email = "user1@email.com" => "user1@email.com" irb(main):004:0> user.valid? User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER(?) LIMIT ? [["email", "user1@email.com"], ["LIMIT", 1]] => false
falseとなることがわかりました。
2.なぜ失敗してしまうのでしょうか? エラーメッセージを確認してみてください。
解答
メッセージを確認しています。
irb(main):007:0> user.errors.messages => {:password=>["can't be blank"]}
パスワード空っぽだめよーって言われてますね。
6.3.3 パスワードの最小文字数
1.有効な名前とメールアドレスでも、パスワードが短すぎるとuserオブジェクトが有効にならないことを確認してみましょう。
解答
パスワードをaaaとして確認してみます。
irb(main):001:0> user = User.new(name: "user2",email: "user2@email.com") => #<User id: nil, name: "user2", email: "user2@email.com", created_at: nil, updated_at: nil, password_digest: nil> irb(main):002:0> user.password = user.password_digest = "aaa" => "aaa" irb(main):003:0> user.valid? User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER(?) LIMIT ? [["email", "user2@email.com"], ["LIMIT", 1]] => false
falseになってますね。
2.上で失敗した時、どんなエラーメッセージになるでしょうか? 確認してみましょう。
解答
irb(main):004:0> user.errors.messages => {:password=>["is too short (minimum is 6 characters)"]}
短すぎるぞーって言われました。
6.3.4 ユーザーの作成と認証
1.コンソールを一度再起動して (userオブジェクトを消去して)、このセクションで作ったuserオブジェクトを検索してみてください。
解答
このセクションと同じようにemailを検索しましょう。
irb(main):001:0> user = User.find_by_email("mhartl@example.com") User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."email" = ? LIMIT ? [["email", "mhartl@example.com"], ["LIMIT", 1]] => #<User id: 1, name: "Michael Hartl", email: "mhartl@example.com", created_at: "2018-07-03 12:39:58", updated_at: "2018-07-03 12:39:58", password_digest: "$2a$10$BWPb8gf1HqTQkVKVWEmbfuEBNKHBk2R29RXtUrQhdL....">
出てきましたね。
2.オブジェクトが検索できたら、名前を新しい文字列に置き換え、saveメソッドで更新してみてください。うまくいきませんね…、なぜうまくいかなかったのでしょうか?
解答
適当にtestuserとでもしてみます。
irb(main):002:0> user.name = "testuser" => "testuser" irb(main):003:0> user.save (0.2ms) SAVEPOINT active_record_1 User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER(?) AND ("users"."id" != ?) LIMIT ? [["email", "mhartl@example.com"], ["id", 1], ["LIMIT", 1]] (0.1ms) ROLLBACK TO SAVEPOINT active_record_1 => false
saveに失敗しました。
メッセージを表示してみましょう。
irb(main):004:0> user.errors.messages => {:password=>["can't be blank", "is too short (minimum is 6 characters)"]}
パスワード空じゃないよ。短すぎるよ。と言われてます。
3.今度は6.1.5で紹介したテクニックを使って、userの名前を更新してみてください。
解答
特定の情報だけを更新したいときはupdate_attributeを使うと更新できます。
irb(main):008:0> user.update_attribute(:name, "testuser") (0.2ms) SAVEPOINT active_record_1 SQL (2.9ms) UPDATE "users" SET "name" = ?, "updated_at" = ? WHERE "users"."id" = ? [["name", "testuser"], ["updated_at", "2018-07-03 12:47:10.113582"], ["id", 1]] (0.1ms) RELEASE SAVEPOINT active_record_1 => true
覚えることが多くなってきましたね。
こんなこともあるんだーって思うくらいで最初は大丈夫だと思いますよー。
実際使う時にここに戻ってこれるようにしておきましょう。