ActiveRecord Validation #2
前回の「ActiveRecord Validation #1」の続き
length
名前通りlengthを検証するヘルパー
require "rails_helper"
class Entry < ActiveRecord::Base
# allow_blankをfalseでminimumが指定されてない場合?においてはminimumが1に設定される模様
validates :name, length: {
minimum: 2,
maximum: 8,
too_short: "%{attribute} too short %{count} words",
too_long: "%{attribute} too long %{count} words",
}
end
describe Entry do
it "lengthのテスト(minimum)" do
entry = Entry.new({ name: "a" })
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).to eq([:name, ["Name too short 2 words"]])
end
it "lengthのテスト(maximum)" do
entry = Entry.new({ name: "x" * 10 })
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).to eq([:name, ["Name too long 8 words"]])
end
end
っていう感じでminimum/maximumを設定する事でlengthによる制限をチェック出来る。isオプションを使えば指定したlengthでのチェックをする事も出来るし
class Entry < ActiveRecord::Base
validates :name, length: { in: 2..8 }
end
な感じでinオプションでRange型で指定する事も出来る模様
numericality
数値かどうかを検証するヘルパー
require "rails_helper"
class Entry < ActiveRecord::Base
validates :age, numericality: { only_integer: true }
end
describe Entry do
it "numericalityのテスト" do
expect(Entry.new({ age: 1 }).valid?).to eq true
entry = Entry.new({ age: 1.0 })
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).to eq [:age, ["must be an integer"]]
end
end
てな感じでonly_integerを設定すると整数値は可能だけど小数点型等を指定するとエラーになる
又、指定した値より大きいかとかodd/evenか等も検証する事が可能
require "rails_helper"
class Entry < ActiveRecord::Base
validates :age, numericality: {
#greater_than: 0,
greater_than_or_equal_to: 1,
less_than: 10,
# odd: true
even: true
}
end
describe Entry do
it "numericalityのテスト" do
expect(Entry.new({ age: 2 }).valid?).to eq true
expect(Entry.new({ age: 2.0 }).valid?).to eq true
# greater_thanオプションによりfalseになる
expect(Entry.new({ age: 0 }).valid?).to eq false
# less_thanオプションによりfalse
expect(Entry.new({ age: 10 }).valid?).to eq false
# evenで少数点型で指定したとしてもto_iされて評価される模様
expect(Entry.new({ age: 2.1 }).valid?).to eq true
entry = Entry.new
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).to eq([:age, ["is not a number"]])
end
end
absence
空白かどうかを検証するヘルパー。presenceの逆的な感じ?
require "rails_helper"
class Entry < ActiveRecord::Base
validates :name, absence: true
end
describe Entry do
it "absenceのテスト" do
expect(Entry.new.valid?).to eq true
entry = Entry.new({ name: "hoge" })
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).to eq [:name, ["must be blank"]]
end
end
uniqueness
カラムに対する一意性をチェック出来るヘルパー
require "rails_helper"
class Entry < ActiveRecord::Base
validates :name, uniqueness: { case_sensitive: true }
end
describe Entry do
fixtures :entry
it "uniquenessのテスト" do
# case_sensitiveオプションをtrueにするとテストが通る
expect(Entry.new({ name: "HOGE" }).valid?).to eq true
entry = Entry.new({ name: "hoge" })
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).to eq [:name, ["has already been taken"]]
end
end
っていう感じでcase_sensitiveオプションで大文字小文字を評価するかを指定出来る。上記の場合であると
begin transaction
SELECT
1 AS one
FROM
"entries"
WHERE
"entries"."name" = "HOGE"
LIMIT 1
SELECT
1 AS one
FROM
"entries"
WHERE
"entries"."name" = "hoge"
LIMIT 1
rollback transaction
っていうような感じなSQLが発行(fixtures関係のSQLは除外)される。でcase_sensitiveオプションを変えてテストが成功するように修正した場合のSQLは
begin transaction
SELECT
1 AS one
FROM
"entries"
WHERE
LOWER("entries"."name") = LOWER("HOGE")
LIMIT 1
SELECT
1 AS one
FROM
"entries"
WHERE
LOWER("entries"."name") = LOWER("hoge")
LIMIT 1
rollback transaction
というようにcase_sensitiveをfalseにした場合は大文字小文字かどうかを評価しないので値を検索する際にはlowerされて検索されて検証される
又、uniquenessはscopeを使う事で複合一意制約を利用する事も出来る。詳しくは「Railsの複数一意制約について」が参考になるかと
とまぁ基本的なバリデーションヘルパーな所はこれで終わり。まだまだ続く