Try T.M Engineer Blog

「アウトプットする事は大事だ」と思って初めたブログ、プログラミング、独り語り、etc

【Ruby on Railsチュートリアル(第4版)】第6章 ユーザーのモデルを作成する(演習と解答)

はじめに

このブログ記事は、私(Kodak)自身のRailsの勉強記録として書いています。
Ruby on Railsチュートリアル』の演習と解答をもくもくと書いているだけの記事なので、興味の無い方は軽くスルーしてあげてください。他にも、まだ『Railsチュートリアル』の演習に挑戦していない方、これから『Railsチュートリアル』をやるぞ!という方は(演習の解答の)ネタバレになりますので、スルーしてください。

Ruby on Rails チュートリアルとは?

Ruby業界でRailsを使い始めるなら、まず最初に初めるRails入門サイトです。
電子書籍版は有料ですが、Webサイトにあるオンライン版は無料なので、誰でも読む(Railsにチャレンジする)事ができます。
railstutorial.jp
全部で14章あり、かなりのボリュームですが、これを読む事でRailsの基礎を学ぶ事ができ、ちょっとしたWebアプリケーションを作れるレベルにはなれる?とのこと。
各章毎に演習問題が複数あり、これを解いていく事でRailsへの理解を深めていく事ができる様になっています。

環境について

Ruby 2.5.0-dev
Rails 5.1.4
バージョン管理ツール:GitHub(https://github.com/Kodak4400)

演習と解答

6.1.1 データベースの移行<演習>
1. Railsはdb/ディレクトリの中にあるschema.rbというファイルを使っています。これはデータベースの構造 (スキーマ (schema) と呼びます) を追跡するために使われます。さて、あなたの環境にあるdb/schema.rbの内容を調べ、その内容とマイグレーションファイル (リスト 6.2) の内容を比べてみてください。
【解答】以下の通り。

$ ls -l db/schema.rb
-rw-r--r--  1 Kodak  staff  961  7 21 18:20 db/schema.rb
$ cat db/schema.rb
ActiveRecord::Schema.define(version: 20180721091744) do

  create_table "users", force: :cascade do |t|
    t.string "name"
    t.string "email"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

end
$

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:migrate
== 20180721091744 CreateUsers: migrating ======================================
-- create_table(:users)
   -> 0.0008s
== 20180721091744 CreateUsers: migrated (0.0009s) =============================
$ rails db:rollback
== 20180721091744 CreateUsers: reverting ======================================
-- drop_table(:users)
   -> 0.0008s
== 20180721091744 CreateUsers: reverted (0.0051s) =============================

$
$ ls -l db/schema.rb
-rw-r--r--  1 Kodak  staff  771  7 21 18:30 db/schema.rb
$ cat db/schema.rb
ActiveRecord::Schema.define(version: 0) do

end
$

3. もう一度rails db:migrateコマンドを実行し、db/schema.rbの内容が元に戻ったことを確認してください。
【解答】以下の通り。

$ rails db:migrate
== 20180721091744 CreateUsers: migrating ======================================
-- create_table(:users)
   -> 0.0011s
== 20180721091744 CreateUsers: migrated (0.0012s) =============================

$ ls -l db/schema.rb
-rw-r--r--  1 Kodak  staff  961  7 21 18:31 db/schema.rb
$ cat db/schema.rb
ActiveRecord::Schema.define(version: 20180721091744) do

  create_table "users", force: :cascade do |t|
    t.string "name"
    t.string "email"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

end
$

6.1.2 modelファイル<演習>
1. Railsコンソールを開き、User.newでUserクラスのオブジェクトが生成されること、そしてそのオブジェクトがApplicationRecordを継承していることを確認してみてください (ヒント: 4.4.4で紹介したテクニックを使ってみてください)。
【解答】以下の通り。

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.class
=> User(id: integer, name: string, email: string, created_at: datetime, updated_at: datetime)
irb(main):003:0> user.class.superclass
=> ApplicationRecord(abstract)

2. 同様にして、ApplicationRecordがActiveRecord::Baseを継承していることについて確認してみてください。
【解答】以下の通り。

irb(main):003:0> user.class.superclass
=> ApplicationRecord(abstract)
irb(main):004:0> user.class.superclass.superclass
=> ActiveRecord::Base
irb(main):005:0> user.class.superclass.superclass.superclass

6.1.3 ユーザーオブジェクトを作成する<演習>
1. user.nameとuser.emailが、どちらもStringクラスのインスタンスであることを確認してみてください。
【解答】以下の通り。

irb(main):022:0> user.name.class
=> String
irb(main):023:0> user.email.class
=> String
irb(main):024:0>

2. created_atとupdated_atは、どのクラスのインスタンスでしょうか?
【解答】以下の通り。

irb(main):024:0> user.created_at.class
=> ActiveSupport::TimeWithZone
irb(main):025:0> user.updated_at.class
=> ActiveSupport::TimeWithZone
irb(main):026:0>

6.1.4 ユーザーオブジェクトを検索する<演習>
1. nameを使ってユーザーオブジェクトを検索してみてください。また、 find_by_nameメソッドが使えることも確認してみてください (古いRailsアプリケーションでは、古いタイプのfind_byをよく見かけることでしょう)。
【解答】以下の通り。

irb(main):039:0> User.find_by(name:"Mishael Hartl")
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."name" = ? LIMIT ?  [["name", "Mishael Hartl"], ["LIMIT", 1]]
=> #<User id: 1, name: "Mishael Hartl", email: "mhartl@example.com", created_at: "2018-07-21 11:57:36", updated_at: "2018-07-21 11:57:36">
irb(main):040:0> User.find_by_name("Mishael Hartl")
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."name" = ? LIMIT ?  [["name", "Mishael Hartl"], ["LIMIT", 1]]
=> #<User id: 1, name: "Mishael Hartl", email: "mhartl@example.com", created_at: "2018-07-21 11:57:36", updated_at: "2018-07-21 11:57:36">
irb(main):041:0>

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

irb(main):041:0> User.all.class
=> User::ActiveRecord_Relation
irb(main):042:0>

3. User.allに対してlengthメソッドを呼び出すと、その長さを求められることを確認してみてください (4.2.3)。Rubyの性質として、そのクラスを詳しく知らなくてもなんとなくオブジェクトをどう扱えば良いかわかる、という性質があります。これをダックタイピング (duck typing) と呼び、よく次のような格言で言い表されています「もしアヒルのような容姿で、アヒルのように鳴くのであれば、それはもうアヒルだろう」。(訳注: そういえばRubyKaigi 2016の基調講演で、Ruby作者のMatzがダックタイピングについて説明していました。2〜3分の短くて分かりやすい説明なので、ぜひ視聴してみてください!)
【解答】以下の通り。

irb(main):042:0> User.all.length
  User Load (0.1ms)  SELECT "users".* FROM "users"
=> 2
irb(main):043:0>

6.1.5 ユーザーオブジェクトを更新する<演習>
1. userオブジェクトへの代入を使ってname属性を使って更新し、saveで保存してみてください。
【解答】以下の通り。

irb(main):070:0> user
=> #<User id: 1, name: "El Duderino", email: "dude@abides.org", created_at: "2018-07-21 11:57:36", updated_at: "2018-07-21 12:21:52">
irb(main):071:0> user.name = "Kodak"
=> "Kodak"
irb(main):072:0> user.save
   (0.1ms)  SAVEPOINT active_record_1
  SQL (0.1ms)  UPDATE "users" SET "name" = ?, "updated_at" = ? WHERE "users"."id" = ?  [["name", "Kodak"], ["updated_at", "2018-07-21 12:25:47.913562"], ["id", 1]]
   (0.1ms)  RELEASE SAVEPOINT active_record_1
=> true
irb(main):073:0> user
=> #<User id: 1, name: "Kodak", email: "dude@abides.org", created_at: "2018-07-21 11:57:36", updated_at: "2018-07-21 12:25:47">
irb(main):074:0>

2. 今度はupdate_attributesを使って、email属性を更新および保存してみてください。
【解答】以下の通り。

irb(main):074:0> user
=> #<User id: 1, name: "Kodak", email: "dude@abides.org", created_at: "2018-07-21 11:57:36", updated_at: "2018-07-21 12:25:47">
irb(main):075:0> user.update_attribute(:email, "Kodak@example.com")
   (0.1ms)  SAVEPOINT active_record_1
  SQL (0.1ms)  UPDATE "users" SET "email" = ?, "updated_at" = ? WHERE "users"."id" = ?  [["email", "Kodak@example.com"], ["updated_at", "2018-07-21 12:27:12.787655"], ["id", 1]]
   (0.1ms)  RELEASE SAVEPOINT active_record_1
=> true
irb(main):076:0> user.save
   (0.1ms)  SAVEPOINT active_record_1
   (0.1ms)  RELEASE SAVEPOINT active_record_1
=> true
irb(main):077:0> user
=> #<User id: 1, name: "Kodak", email: "Kodak@example.com", created_at: "2018-07-21 11:57:36", updated_at: "2018-07-21 12:27:12">
irb(main):078:0>

3. 同様にして、マジックカラムであるcreated_atも直接更新できることを確認してみてください。ヒント: 更新するときは「1.year.ago」を使うと便利です。これはRails流の時間指定の1つで、現在の時刻から1年前の時間を算出してくれます。
【解答】以下の通り。

irb(main):079:0> user
=> #<User id: 1, name: "Kodak", email: "Kodak@example.com", created_at: "2018-07-21 11:57:36", updated_at: "2018-07-21 12:27:12">
irb(main):080:0> 1.year.ago
=> Fri, 21 Jul 2017 12:30:16 UTC +00:00
irb(main):081:0> user.update_attribute(:updated_at, 1.year.ago)
   (0.1ms)  SAVEPOINT active_record_1
  SQL (0.1ms)  UPDATE "users" SET "updated_at" = ? WHERE "users"."id" = ?  [["updated_at", "2017-07-21 12:30:54.388296"], ["id", 1]]
   (0.1ms)  RELEASE SAVEPOINT active_record_1
=> true
irb(main):082:0> user.save
   (0.1ms)  SAVEPOINT active_record_1
   (0.1ms)  RELEASE SAVEPOINT active_record_1
=> true
irb(main):083:0> user
=> #<User id: 1, name: "Kodak", email: "Kodak@example.com", created_at: "2018-07-21 11:57:36", updated_at: "2017-07-21 12:30:54">
irb(main):084:0>

6.2.1 有効性を検証する<演習>
1. コンソールから、新しく生成したuserオブジェクトが有効 (valid) であることを確認してみましょう。
【解答】以下の通り。

$ rails console --sandbox
Loading test environment in sandbox (Rails 5.1.4)
Any modifications you make will be rolled back on exit
irb(main):001:0> user = User.new(name: "Example User", email: "user@example.com")
=> #<User id: nil, name: "Example User", email: "user@example.com", created_at: nil, updated_at: nil>
irb(main):002:0> user.valid?
=> true
irb(main):003:0>

2. 6.1.3で生成したuserオブジェクトも有効であるかどうか、確認してみましょう。
【解答】以下の通り。

irb(main):006: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):007:0> user.valid?
=> true
irb(main):008:0>

6.2.2 存在性を検証する<演習>
1. 新しいユーザーuを作成し、作成した時点では有効ではない (invalid) ことを確認してください。なぜ有効ではないのでしょうか? エラーメッセージを確認してみましょう。
【解答】以下の通り。

$ rails console --sandbox
Loading test environment in sandbox (Rails 5.1.4)
Any modifications you make will be rolled back on exit
irb(main):001:0> u = User.new(name:"", email:"")
=> #<User id: nil, name: "", email: "", created_at: nil, updated_at: nil>
irb(main):002:0> u.valid?
=> false
irb(main):003:0> u.errors.full_messages
=> ["Name can't be blank", "Email can't be blank"]
irb(main):004:0>

2. u.errors.messagesを実行すると、ハッシュ形式でエラーが取得できることを確認してください。emailに関するエラー情報だけを取得したい場合、どうやって取得すれば良いでしょうか?
【解答】以下の通り。

irb(main):023:0> u.errors.messages
=> {:name=>["can't be blank"], :email=>["can't be blank"]}
irb(main):024:0> u.errors.messages[:email]
=> ["can't be blank"]
irb(main):025:0>

6.2.3 長さを検証する<演習> 1. 長すぎるnameとemail属性を持ったuserオブジェクトを生成し、有効でないことを確認してみましょう。
【解答】以下の通り。

irb(main):001:0> user = User.new(name:"a"*51, email:"a"*244 + "@example.com")
=> #<User id: nil, name: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...", email: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...", created_at: nil, updated_at: nil>
irb(main):002:0> user.valid?
=> false
irb(main):003:0>

2. 長さに関するバリデーションが失敗した時、どんなエラーメッセージが生成されるでしょうか? 確認してみてください。
【解答】以下の通り。

irb(main):003:0> user.errors.messages
=> {:name=>["is too long (maximum is 50 characters)"], :email=>["is too long (maximum is 255 characters)"]}
irb(main):004:0> user.errors.full_messages
=> ["Name is too long (maximum is 50 characters)", "Email is too long (maximum is 255 characters)"]
irb(main):005:0>

6.2.4 フォーマットを検証する<演習>
1. リスト 6.18にある有効なメールアドレスのリストと、リスト 6.19にある無効なメールアドレスのリストをRubularのYour test string:に転記してみてください。その後、リスト 6.21の正規表現をYour regular expression:に転記して、有効なメールアドレスのみがすべてマッチし、無効なメールアドレスはすべてマッチしないことを確認してみましょう。
【解答】以下の通り。
f:id:special-moucom:20180804222240p:plain

2. 先ほど触れたように、リスト 6.21のメールアドレスチェックする正規表現は、foo@bar..comのようにドットが連続した無効なメールアドレスを許容してしまいます。まずは、このメールアドレスをリスト 6.19の無効なメールアドレスリストに追加し、これによってテストが失敗することを確認してください。次に、リスト 6.23で示した、少し複雑な正規表現を使ってこのテストがパスすることを確認してください。 【解答】以下の通り。

#### test/models/user_test.rb  
 
   test "email validation should reject invalid addresses" do
     valid_addresses = %w[user@example,com user_at_foo.org user.name@example.
                                foo@bar_baz.com foo@bar+baz.com foo@bar..com]
     valid_addresses.each do |valid_address|
       @user.email = valid_address
       assert_not @user.valid?, "#{valid_address.inspect} should be invalid"
     end
   end
$ rails test:models
Failure:
"foo@bar..com" should be invalid
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.042992s, 162.8210 runs/s, 372.1623 assertions/s.
7 runs, 16 assertions, 0 failures, 0 errors, 0 skips

3. foo@bar..comをRubularのメールアドレスのリストに追加し、リスト 6.23の正規表現をRubularで使ってみてください。有効なメールアドレスのみがすべてマッチし、無効なメールアドレスはすべてマッチしないことを確認してみましょう。
【解答】以下の通り。
f:id:special-moucom:20180804222250p:plain

6.2.5 一意性を検証する<演習>
1. リスト 6.33を参考に、メールアドレスを小文字にするテストをリスト 6.32に追加してみましょう。ちなみに追加するテストコードでは、データベースの値に合わせて更新するreloadメソッドと、値が一致しているかどうか確認するassert_equalメソッドを使っています。リスト 6.33のテストがうまく動いているか確認するためにも、before_saveの行をコメントアウトして redになることを、また、コメントアウトを解除すると greenになることを確認してみましょう。
【解答】以下の通り。

### app/models/user.rb
class User < ApplicationRecord
  before_save { self.email = email.downcase }
  validates :name, presence: true, length:{ maximum: 50 }
  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 },
    uniqueness: { case_sensitive:false }
end
### test/models/user_test.rb
  test "email addresses should be saved as lower-case" do
    mixed_case_email = "Foo@ExAPle.CoM"
    @user.email = mixed_case_email
    @user.save
    assert_equal mixed_case_email.downcase, @user.reload.email
  end
end
$ rails t
Finished in 0.516900s, 30.9538 runs/s, 67.7114 assertions/s.
16 runs, 35 assertions, 0 failures, 0 errors, 0 skips
class User < ApplicationRecord
  # before_save { self.email = email.downcase }
  validates :name, presence: true, length:{ maximum: 50 }
  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 },
    uniqueness: { case_sensitive:false }
end
$ rails t
Failure:
Expected: "foo@exaple.com"
  Actual: "Foo@ExAPle.CoM"

2. テストスイートの実行結果を確認しながら、before_saveコールバックをemail.downcase!に書き換えてみましょう。ヒント: メソッドの末尾に!を付け足すことにより、email属性を直接変更できるようになります (リスト 6.34)。
【解答】以下の通り。

### app/models/user.rb
class User < ApplicationRecord
  before_save { email.downcase! }
  validates :name, presence: true, length:{ maximum: 50 }
  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 },
    uniqueness: { case_sensitive:false }
end
$ rails t
Finished in 0.516124s, 31.0003 runs/s, 67.8132 assertions/s.
16 runs, 35 assertions, 0 failures, 0 errors, 0 skips

6.2.5 一意性を検証する<演習>
1. リスト 6.33を参考に、メールアドレスを小文字にするテストをリスト 6.32に追加してみましょう。ちなみに追加するテストコードでは、データベースの値に合わせて更新するreloadメソッドと、値が一致しているかどうか確認するassert_equalメソッドを使っています。リスト 6.33のテストがうまく動いているか確認するためにも、before_saveの行をコメントアウトして redになることを、また、コメントアウトを解除すると greenになることを確認してみましょう。
【解答】以下の通り。

### test/models/user_test.rb
  test "email addresses should be saved as lower-case" do
    mixed_case_email = "Foo@ExAPle.CoM"
    @user.email = mixed_case_email
    @user.save
    assert_equal mixed_case_email.downcase, @user.reload.email
  end
### app/models/user.rb
class User < ApplicationRecord
  # before_save { self.email = email.downcase }
  validates :name, presence: true, length:{ maximum: 50 }
  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 },
    uniqueness: { case_sensitive:false }
  has_secure_password
  validates :password, presence: true, length:{ minimum: 6 }
end
$ rails t
Failure:
Expected: "foo@exaple.com"
  Actual: "Foo@ExAPle.CoM"

2. テストスイートの実行結果を確認しながら、before_saveコールバックをemail.downcase!に書き換えてみましょう。ヒント: メソッドの末尾に!を付け足すことにより、email属性を直接変更できるようになります (リスト 6.34)。
【解答】以下の通り。

### app/models/user.rb
class User < ApplicationRecord
  before_save { email.downcase! }
  validates :name, presence: true, length:{ maximum: 50 }
  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 },
    uniqueness: { case_sensitive:false }
  has_secure_password
  validates :password, presence: true, length:{ minimum: 6 }
end
$ rails t
Finished in 0.631721s, 28.4936 runs/s, 58.5702 assertions/s.
18 runs, 37 assertions, 0 failures, 0 errors, 0 skips

6.3.2 ユーザーがセキュアなパスワードを持っている<演習>
1. この時点では、userオブジェクトに有効な名前とメールアドレスを与えても、valid?で失敗してしまうことを確認してみてください。
【解答】以下の通り。

$ rails console --sandbox
Loading test environment in sandbox (Rails 5.1.4)
Any modifications you make will be rolled back on exit
irb(main):001:0> u = User.new(name:"Kodak", email:"kodak@example.com")
=> #<User id: nil, name: "Kodak", email: "kodak@example.com", created_at: nil, updated_at: nil, password_digest: nil>
irb(main):002:0> u.valid?
  User Exists (0.2ms)  SELECT  1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER(?) LIMIT ?  [["email", "kodak@example.com"], ["LIMIT", 1]]
=> false

2. なぜ失敗してしまうのでしょうか? エラーメッセージを確認してみてください。
【解答】以下の通り。

### Passwordがブランクだから失敗する。
irb(main):003:0> u.errors.full_messages
=> ["Password can't be blank"]
irb(main):004:0>

6.3.3 パスワードの最小文字数<演習>
1. 有効な名前とメールアドレスでも、パスワードが短すぎるとuserオブジェクトが有効にならないことを確認してみましょう。
【解答】以下の通り。

$ rails console --sandbox
Loading test environment in sandbox (Rails 5.1.4)
Any modifications you make will be rolled back on exit
irb(main):001:0> u = User.new(name:"Kodak", email:"kodak@example.com", password:"test", password_confirmation:"test")
=> #<User id: nil, name: "Kodak", email: "kodak@example.com", created_at: nil, updated_at: nil, password_digest: "$2a$04$KRwXzohH1GsunyCijvFyJOEQYRctJ7HPl0ntTxVCCWR...">
irb(main):002:0> u.valid?
  User Exists (0.2ms)  SELECT  1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER(?) LIMIT ?  [["email", "kodak@example.com"], ["LIMIT", 1]]
=> false

2. 上で失敗した時、どんなエラーメッセージになるでしょうか? 確認してみましょう。
【解答】以下の通り。

irb(main):003:0> u.errors.full_messages
=> ["Password is too short (minimum is 6 characters)"]
irb(main):004:0>

6.3.4 ユーザー作成と認証<演習>
1. コンソールを一度再起動して (userオブジェクトを消去して)、このセクションで作ったuserオブジェクトを検索してみてください。
【解答】以下の通り。

$ rails console --sandbox
irb(main):001:0> user = User.find_by(email:"mhartl@example.com")
  User Load (0.4ms)  SELECT  "users".* FROM "users" WHERE "users"."email" = ? LIMIT ?  [["email", "mhartl@example.com"], ["LIMIT", 1]]
=> #<User id: 980190963, name: "Michael Hartl", email: "mhartl@example.com", created_at: "2018-07-29 08:38:46", updated_at: "2018-07-29 08:38:46", password_digest: "$2a$04$9hMkUoiUj89BCHD9zXO1su3v.fv572laOPFjg9i7cUY...">
irb(main):002:0> user
=> #<User id: 980190963, name: "Michael Hartl", email: "mhartl@example.com", created_at: "2018-07-29 08:38:46", updated_at: "2018-07-29 08:38:46", password_digest: "$2a$04$9hMkUoiUj89BCHD9zXO1su3v.fv572laOPFjg9i7cUY...">
irb(main):003:0>

2. オブジェクトが検索できたら、名前を新しい文字列に置き換え、saveメソッドで更新してみてください。うまくいきませんね...、なぜうまくいかなかったのでしょうか?
【解答】以下の通り。

### save時にパスワードの保存を要求するため、検証で失敗している
irb(main):005:0> user.name = "Kodak Hartl"
=> "Kodak Hartl"
irb(main):006:0> user.save
   (0.1ms)  SAVEPOINT active_record_1
  User Exists (0.1ms)  SELECT  1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER(?) AND ("users"."id" != ?) LIMIT ?  [["email", "mhartl@example.com"], ["id", 980190963], ["LIMIT", 1]]
   (0.1ms)  ROLLBACK TO SAVEPOINT active_record_1
=> false
irb(main):007:0>

3. 今度は6.1.5で紹介したテクニックを使って、userの名前を更新してみてください。
【解答】以下の通り。

### update_attributeなら検証を回避できる
irb(main):009:0> user.update_attribute(:name, "Kodak Hartl")
   (0.1ms)  SAVEPOINT active_record_1
  SQL (0.4ms)  UPDATE "users" SET "name" = ?, "updated_at" = ? WHERE "users"."id" = ?  [["name", "Kodak Hartl"], ["updated_at", "2018-07-29 09:06:05.264126"], ["id", 980190963]]
   (0.1ms)  RELEASE SAVEPOINT active_record_1
=> true
irb(main):010:0>