LoginSignup
1
0

More than 1 year has passed since last update.

railsチュートリアル第6章 フォーマットを検証する

Posted at

フォーマットを検証する

name属性の検証には、空文字でない、名前が51文字未満であるという最小限の制約しか与えていませんでした。
email属性の場合は、有効なメールアドレスかどうかを判定するために、もっと厳重な要求を満たさなければなりません
これまでは空のメールアドレスのみを禁止してきましたが、ここではメールアドレスにおなじみのパターンuser@example.comに合っているかどうかも確認することを要求します。
最初に、有効なメールアドレスと無効なメールアドレスのコレクションに対するテストを行いましょう。
このコレクションを作る方法として、次に示すように、文字列の配列を簡単に作れる%w[]という便利なテクニックを知っておくと良いでしょう。

>> %w[foo bar baz]
=> ["foo", "bar", "baz"]
>> addresses = %w[USER@foo.COM THE_US-ER@foo.bar.org  first.last@foo.jp]
=> ["USER@foo.COM", "THE_US-ER@foo.bar.org", "first.last@foo.jp"]
>> addresses.each do |address|
?>   puts address
>> end
USER@foo.COM
THE_US-ER@foo.bar.org
first.last@foo.jp
=> ["USER@foo.COM", "THE_US-ER@foo.bar.org", "first.last@foo.jp"]

eachメソッドを使ってaddresses配列の各要素を繰り返し取り出しました。
このテクニックを学んだことで、基本となるメールアドレスフォーマット検証のテストを書く準備が整いました。

メールアドレスのバリデーションは扱いが難しく、エラーが発生しやすい部分なので、有効なメールアドレスと無効なメールアドレスをいくつか用意して、バリデーション内のエラーを検知していきます。
具体的には、user@example,comのような無効なメールアドレスが弾かれることと、user@example.comのような有効なメールアドレスが通ることを確認しながら、バリデーションを実装していきます。
まずは、有効なメールアドレスを示します。

有効なメールフォーマットをテストする

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

  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

  test "name should not be too long" do
    @user.name = "a" * 51
    #51字以内
    assert_not @user.valid?
  end

  test "email should not be too long" do
    @user.email = "a" * 244 + "@example.com"
    #244字以内
    assert_not @user.valid?
  end

  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
end
assert @user.valid?, "#{valid_address.inspect} should be valid"

(詳細な文字列を調べるために4.3.3で紹介したinspectメソッドを使っています。)
どのメールアドレスで失敗したのかを知ることは非常に便利です。
そこでは、eachメソッドを使って各メールアドレスを順にテストしています。
ループさせずにテストすると、失敗した行番号メールアドレスの行数を照らし合わせて、失敗したメールアドレスを特定するといった作業が発生してしまいます。

次に、user@example,com(ドットではなくカンマになっている)やuser_at_foo.org(アットマーク ‘@’ がない)といった無効なメールアドレスを使って 「無効性(Invalidity)」についてテストしていきます。
エラーメッセージをカスタマイズして、どのメールアドレスで失敗したのかすぐに特定できるようにしておきます。

メールフォーマットの検証に対するテスト

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

  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

  test "name should not be too long" do
    @user.name = "a" * 51
    #51字以内
    assert_not @user.valid?
  end

  test "email should not be too long" do
    @user.email = "a" * 244 + "@example.com"
    #244字以内
    assert_not @user.valid?
  end

  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
end
ubuntu:~/environment/sample_app (modeling-users) $ rails t
Running via Spring preloader in process 8260
Started with run options --seed 20507

 FAIL["test_email_validation_should_reject_invalid_addresses", #<Minitest::Reporters::Suite:0x00007efe74ee67f8 @name="UserTest">, 0.03949682099982965]
 test_email_validation_should_reject_invalid_addresses#UserTest (0.04s)
        "user@example,com" should be invalid
        test/models/user_test.rb:50:in `block (2 levels) in <class:UserTest>'
        test/models/user_test.rb:48:in `each'
        test/models/user_test.rb:48:in `block in <class:UserTest>'

  15/15: [============================] 100% Time: 00:00:02, Time: 00:00:02

Finished in 2.77939s
15 tests, 30 assertions, 1 failures, 0 errors, 0 skips

test_email_validation_should_reject_invalid_addressesがダメらしい。

メールアドレスのフォーマットを検証するためには、次のようにformatというオプションを使います。

validates :email, format: { with: /<regular expression>/ }

このオプションは引数に正規表現(Regular Expression)(regexとも呼ばれます)を取ります。
正規表現は一見謎めいて見えますが、文字列のパターンマッチングにおいては非常に強力な言語です。
つまり、有効なメールアドレスだけにマッチして、無効なメールアドレスにはマッチしない正規表現を組み立てる必要があります。

本チュートリアルでは、実践的でシンプルな正規表現を採用します。これがその正規表現です。

VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i

正規表現を本当に理解するためには実際に使って見るのが一番です。
例えばRubularという対話的に正規表現を試せるWebサイトがあります。
このWebサイトはインタラクティブ性に富んだインターフェイスを持っていて、また、正規表現のクイックリファレンスも兼ね備えています。Rubularをブラウザで開き、実際に試してみることを強くお勧めします。
正規表現は、読んで学ぶより対話的に学んだほうが早いです。

正規表現を適用してemailのフォーマットを検証した結果を示します。

メールフォーマットを正規表現で検証する

class User < ApplicationRecord
  validates :name,  presence: true, length: { maximum: 50 }
  #属性はname,属性の存在を検証、 最大50字まで
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
  validates :email, presence: true, length: { maximum: 255 },
  #最大255字まで
                    format: { with: VALID_EMAIL_REGEX }
end

正規表現VALID_EMAIL_REGEXは定数です。
大文字で始まる名前はRubyでは定数を意味します。次のコードは、

VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
  validates :email, presence: true, length: { maximum: 255 },
                    format: { with: VALID_EMAIL_REGEX }

これで、このパターンに一致するメールアドレスだけが有効であることをチェックできるようになります。
ただ上の正規表現には、少しだけ残念な点があります。
それはfoo@bar..comのようなドットの連続を誤りとして検出できない、という点です。
正規表現を修正すると直りますが、これについては演習に持ち越すことにしましょう
(訳注: ドットの連続だけでなく、国際化ドメインにも対応できた方が良いでしょう。指摘してくれた@znzさん、ありがとうございます!)。

この時点では、テストは green になるはずです。

Started with run options --seed 41242

  7/7: [==============================] 100% Time: 00:00:00, Time: 00:00:00

Finished in 0.03163s
7 tests, 15 assertions, 0 failures, 0 errors, 0 skips

演習

1.リスト 6.18にある有効なメールアドレスのリストと、リスト 6.19にある無効なメールアドレスのリストをRubularのYour test string:に転記してみてください。
lその後、リスト 6.21の正規表現をYour regular expression:に転記して、有効なメールアドレスのみがすべてマッチし、無効なメールアドレスはすべてマッチしないことを確認してみましょう。

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

3.foo@bar..comをRubularのメールアドレスのリストに追加し、リスト 6.23の正規表現をRubularで使ってみてください。有効なメールアドレスのみがすべてマッチし、無効なメールアドレスはすべてマッチしないことを確認してみましょう。

1からNo matchesになり、できなかった。

1
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
1
0