ActiveRecord Validation #1

2014-08-22T00:00:00+00:00 rspec Ruby Rails

公式ドキュメント: http://guides.rubyonrails.org/active_record_validations.html

公式ドキュメントを読みつつ進めてみようかと。ただやたらと長いので何回かに分けて書く予定

基本的な使い方

require "rails_helper"

class Entry < ActiveRecord::Base
  validates :name, presence: true
end

describe Entry do
  it "(valid?|invalid?)メソッド" do
    entry = Entry.new

    # valid等を実行する前だとerrosはempty
    expect(entry.errors).to be_empty

    expect(entry.valid?).to eq false
    expect(entry.invalid?).to eq true

    # valid等を処理した後だとerrorsには検証エラーが入る
    errors = entry.errors
    expect(errors).not_to be_empty

    messages = errors.messages
    expect(messages).not_to be_empty

    message = messages.first
    expect(message).not_to be_nil
    expect(message).to eq([:name, ["can"t be blank"]])
  end
end

っていうような感じになる。valid等を動かさなくてもsaveやupdate等のメソッドを実行すると検証エラーな場合はfalseが返り、破壊的メソッドとして実行するとActiveRecord::RecordInvalidがスローされる模様

っていう感じで、基本的な事は終わり。presence等のValidation Helpersな所を進める

presence

.blank?でチェックされるバリデーションルール。上記の基本的な所なセクションでほとんど買いちゃってるけど

require "rails_helper"

class Entry < ActiveRecord::Base
  validates :name, presence: { message: "can`t be empty" }
end

describe Entry do
  it "presenceのテスト" do
    entry = Entry.new
    expect(entry.save).to eq false

    errors = entry.errors
    expect(errors).not_to be_empty

    messages = errors.messages
    expect(messages).not_to be_empty

    message = messages.first
    expect(message).not_to be_nil
    expect(message).to eq([:name, ["can`t be empty"]])
  end
end

っていうようにエラーメッセージ辺りを変える事も可能。特にpresenceに限った機能じゃないはずなので(ry

acceptance

「規約に同意する」等の機能があるようなチェックボックス等によるデータ処理を検証するバリデーションヘルパーな模様。デフォルトであれば「"1″」を挿入しているかどうかで検証される(変更可能)。又、オプションで指定しない限りはnilじゃない場合にのみバリデーションが作用するようになる模様

require "rails_helper"

class Entry < ActiveRecord::Base
  validates :terms_of_service, acceptance: true
end

describe Entry do
  it "acceptanceのテスト" do
    entry = Entry.new({ terms_of_service: "1" })
    expect(entry.valid?).to be true
  end

  it "terms_of_serviceを指定しない場合" do
    expect(Entry.new.valid?).to eq true
  end
end

このテストは通る。2つ目のテストでterms_of_serviceを指定しなくてもvalid?がtrueになるのはnilな状態であればバリデーションが作用しない為かと。なので

class Entry < ActiveRecord::Base
  validates :terms_of_service, acceptance: true, allow_nil: false
end

とした場合には上記でテストは成功する2つ目が成功しなくなる。allow_nilはグローバルオプション?だと思われるのでacceptanceに限って指定出来る物ではないのではと。でデフォルトだと"1″を入れなければならないが、acceptanceオプションを設定する事で変更可能

require "rails_helper"

class Entry < ActiveRecord::Base
  validates :terms_of_service, acceptance: { accept: "yes" }, allow_nil: false
end

describe Entry do
  it "acceptanceのテスト" do
    entry = Entry.new({ terms_of_service: "yes" })
    expect(entry.valid?).to be true
  end

  it "terms_of_serviceを指定しない場合" do
    expect(Entry.new.valid?).to eq false
  end
end

っていうような感じでacceptanceオプションを修正することで"1″以外で作用させる事も可能

んまぁ規約に同意するような機能とかなら同意してないならDB処理しないような仕組みをやれば良いだけなので、こういうのをする必要性はあんま無いと思うけど「メールによるお知らせを受け取る」ような設定オプションとかであればこういうのを使えば良いのではと(そういう場合はallow_nilを設定するべきではないはず)

confirmation

require "rails_helper"

class Entry < ActiveRecord::Base
  validates :email, confirmation: true
end

describe Entry do
  it "confirmationのテスト" do
    entry = Entry.new({
      email: "A@example.com",
      email_confirmation: "B@example.com"
    })
    expect(entry.valid?).to eq false

    errors = entry.errors
    expect(errors).not_to be_empty

    messages = errors.messages
    expect(messages).not_to be_empty

    message = messages.first
    expect(message).not_to be_nil
    expect(message).to eq [:email_confirmation, ["doesn"t match Email"]]
  end

  it "email_confirmationを指定しない場合" do
    entry = Entry.new({ email: "A@example.com" })
    expect(entry.valid?).to eq true
  end
end

ってな感じでconfirmation validation helperを使っているのに対して、_confirmationな仮想的属性の値を比較して同一かをチェック出来る。但しその仮想的属性がnilでは無い場合にのみチェックされる模様なので、2つ目のテストではemail_confirmationを指定してない為にバリデーションが作用しない為trueが返るような感じかと

exclusion

指定した項目が入ってはいけない場合のようなケースを検証出来る。逆がinclusion

require "rails_helper"

class Entry < ActiveRecord::Base
  validates :subdomain, exclusion: { in: %w(www blog) }
end

describe Entry do
  it "exclusionのテスト" do
    expect(Entry.new({ subdomain: "user" }).valid?).to eq true
    expect(Entry.new({ subdomain: "www" }).valid?).to eq false
    expect(Entry.new({ subdomain: "blog" }).valid?).to eq false
  end
end

inで指定したリストに該当するのが入るとバリデーションとしては不整合という形になる模様。恐らくはnilな場合だと検証が作用しないんかと思われる

inclusion

上記にあるexclusionの反対であるinclusion。リストにマッチする値のみが許可されるようなケースで使うっぽい

require "rails_helper"

class Entry < ActiveRecord::Base
  validates :subdomain, inclusion: { in: %w(www blog) }
end

describe Entry do
  it "inclusionのテスト" do
    expect(Entry.new({ subdomain: "www" }).valid?).to eq true
    expect(Entry.new({ subdomain: "blog" }).valid?).to eq true
    expect(Entry.new({ subdomain: "user" }).valid?).to eq false
  end
end

inで指定してあるのみ許容される。

format

正規表現とかで値の検証を行うようなパターンの場合に使う

require "rails_helper"

class Entry < ActiveRecord::Base
  validates :postal_code, format: { with: /\A[\d]{3}\-[\d]{4}\z/ }
end

describe Entry do
  it "formatのテスト" do
    expect(Entry.new({ postal_code: "123-4567" }).valid?).to eq true

    entry = Entry.new({ postal_code: "123-456a" })
    expect(entry.errors).to be_empty
    expect(entry.valid?).to eq false

    errors = entry.errors
    expect(errors).not_to be_empty

    messages = errors.messages
    expect(messages).not_to be_empty

    message = messages.first
    expect(message).not_to be_nil
    expect(message).to eq([:postal_code, ["is invalid"]])
  end
end

てな感じでwithで指定した正規表現で値をチェック出来る。

とりあえず今回は以上。続きは後日

ActiveRecord Validation #2 JAX-RSをやってみる (16) - ParamConverter -