【Rails】Userモデルの基本的なバリデーションとテスト【Rails Tutorial 6章まとめ】

##最初のモデルが有効であるかのテスト
生成したモデルの属性に値を与え、インスタンスが有効であるかをテストする（バリデーションはまだ無い）。

```test/models/user_test.rb
require 'test_helper'

class UserTest < ActiveSupport::TestCase

  def setup
    @user = User.new(name: "Example User", email: "user@example.com")
  end

  test "should be valid" do
    assert @user.valid?
  end
end
```

assertは引数の論理値がtrueであることを確認する。
assert_notはその逆で、falseであることを確認する。

##存在性の検証(presence)
name属性とemail属性は必ず存在していなければならない。
そこで、バリデーションを設定して各属性が空白の場合は有効でないようにする。

テスト駆動開発で進めていくので、バリデーションを設定する前に、バリデーションが無ければ失敗するテストを書く。

```test/models/user_test.rb

  test "name should be present" do
    @user.name = "  "
    assert_not @user.valid?
  end

  test "email should be present" do
    @user.email = "  "
    assert_not @user.valid?
  end
```

nameとemailにそれぞれ空白を入れる。
バリデーションが無いので@user.valid?はtrueを返し、assert_notに反するため、テストは失敗する。

テストを成功させるために、Userモデルにバリデーションを設定する。

```app/models/user.rb
class User < ApplicationRecord
  validates :name, presence: true
  validates :email, presence: true
end
```
テストをして、成功することを確認しておく。

##長さの制限
nameとemailは長すぎないほうが良い。
長すぎるnameとemailを制限するバリデーションを、テストを書いてから設定する。

```test/models/user_test.rb
  test "name should not be too long" do
    @user.name = "a" * 51
    assert_not @user.valid?
  end

  test "email should not be too long" do
    @user.email = "a" * 244 + "@example.com"
    assert_not @user.valid?
  end
```
nameは５０文字まで、emailはデータベースの文字列の限界である２５５文字までとする。
そこでnameに５１文字、emailに２５６文字を入れておく。

```app/models/user.rb
class User < ApplicationRecord
  validates :name,  presence: true, length: { maximum: 50 }
  validates :email, presence: true, length: { maximum: 255 }
end
```

presenceオプションとlengthオプションはそれぞれをキーとする一つのハッシュだが、validatesメソッドの最後の引数なので、{}は無くてもよい。
lengthキーの値はハッシュなので、{}が必要である。

テストをして、成功することを確認しておく。

##emailのフォーマットの検証
現在のままではemailにメールアドレス以外を入れても保存できてしまうので、フォーマットを制限する。

バリデーションの前に、有効なメールアドレスを確認するテストと、無効なメールアドレスを確認するテストを書く。

```test/models/user_test.rb
  test "email validation should accept valid addresses" do
    valid_addresses = %w[user@example.com USER@foo.COM A_US-ER@foo.bar.org
                         first.last@foo.jp alice+bob@baz.cn]
    valid_addresses.each do |valid_address|
      @user.email = valid_address
      assert @user.valid?, "#{valid_address.inspect} should be valid"
    end
  end

  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]
    invalid_addresses.each do |invalid_address|
      @user.email = invalid_address
      assert_not @user.valid?, "#{invalid_address.inspect} should be invalid"
    end
  end
```
変数にいくつかの有効なメールアドレスを配列にして代入し、eachメソッドを使ってそれぞれのメールアドレスを@user.emailに代入、assertで有効であることを確認する。
無効なメールアドレスのほうのテストはその逆である。
まだバリデーションが無いので、上のテストは成功し、下のテストは失敗する（無効なアドレスも有効と見なされるから）。

assertの第二引数に文字列を与えると、テストが失敗した際にエラーメッセージとして表示することができる。
inspectメソッドは「オブジェクトを分かりやすい文字列にして返す」メソッドらしいが、イマイチよくわからない。

なお、%w[]を使うと、文字列の配列を簡単に作ることができる。

```
>> %w[foo bar baz]
=> ["foo", "bar", "baz"]
```

###フォーマットの設定
フォーマットを設定するためには、formatオプションを使う。

```
validates :email, format: { with: /<regular expression>/ }
```
/\<regular expression>/のところに正しいメールアドレスを表す正規表現（Regurar Expression, regex）を入れる。
正規表現を理解する必要は今のところ無いので、コピペして以下のようにする。

```app/models/user.rb
class User < ApplicationRecord
  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 }
end
```

テストをして、成功することを確認しておく。