Add `validate_uniqueness_of_(:foo).allow_blank`
This re-applies fcbc16e7d6
.
This commit is contained in:
parent
47a0392b77
commit
0e2e9c4519
4
NEWS.md
4
NEWS.md
|
@ -41,6 +41,8 @@
|
|||
### Features
|
||||
|
||||
* Add ability to test `:primary_key` option on associations. ([#597])
|
||||
* Add `allow_blank` qualifier to `validate_uniqueness_of` to complement
|
||||
the `allow_blank` option.
|
||||
|
||||
### Improvements
|
||||
|
||||
|
@ -125,8 +127,6 @@
|
|||
from `validate_uniqueness_of`, your best bet continues to be creating a record
|
||||
manually and calling `validate_uniqueness_of` on that instead.
|
||||
|
||||
### Improvements
|
||||
|
||||
* The majority of warnings that the gem produced have been removed. The gem
|
||||
still produces warnings under Ruby 1.9.3; we will address this in a future
|
||||
release.
|
||||
|
|
|
@ -171,6 +171,26 @@ module Shoulda
|
|||
#
|
||||
# @return [ValidateUniquenessOfMatcher]
|
||||
#
|
||||
# ##### allow_blank
|
||||
#
|
||||
# Use `allow_blank` to assert that the attribute allows a blank value.
|
||||
#
|
||||
# class Post < ActiveRecord::Base
|
||||
# validates_uniqueness_of :author_id, allow_blank: true
|
||||
# end
|
||||
#
|
||||
# # RSpec
|
||||
# describe Post do
|
||||
# it { should validate_uniqueness_of(:author_id).allow_blank }
|
||||
# end
|
||||
#
|
||||
# # Test::Unit
|
||||
# class PostTest < ActiveSupport::TestCase
|
||||
# should validate_uniqueness_of(:author_id).allow_blank
|
||||
# end
|
||||
#
|
||||
# @return [ValidateUniquenessOfMatcher]
|
||||
#
|
||||
def validate_uniqueness_of(attr)
|
||||
ValidateUniquenessOfMatcher.new(attr)
|
||||
end
|
||||
|
@ -204,6 +224,11 @@ module Shoulda
|
|||
self
|
||||
end
|
||||
|
||||
def allow_blank
|
||||
@options[:allow_blank] = true
|
||||
self
|
||||
end
|
||||
|
||||
def description
|
||||
result = "require "
|
||||
result << "case sensitive " unless @options[:case_insensitive]
|
||||
|
@ -218,9 +243,10 @@ module Shoulda
|
|||
@expected_message ||= :taken
|
||||
|
||||
set_scoped_attributes &&
|
||||
validate_everything_except_duplicate_nils? &&
|
||||
validate_everything_except_duplicate_nils_or_blanks? &&
|
||||
validate_after_scope_change? &&
|
||||
allows_nil?
|
||||
allows_nil? &&
|
||||
allows_blank?
|
||||
ensure
|
||||
Uniqueness::TestModels.remove_all
|
||||
end
|
||||
|
@ -236,6 +262,15 @@ module Shoulda
|
|||
end
|
||||
end
|
||||
|
||||
def allows_blank?
|
||||
if @options[:allow_blank]
|
||||
ensure_blank_record_in_database
|
||||
allows_value_of('', @expected_message)
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
def existing_record
|
||||
@existing_record ||= first_instance
|
||||
end
|
||||
|
@ -250,19 +285,23 @@ module Shoulda
|
|||
end
|
||||
end
|
||||
|
||||
def ensure_blank_record_in_database
|
||||
unless existing_record_is_blank?
|
||||
create_record_in_database(blank_value: true)
|
||||
end
|
||||
end
|
||||
|
||||
def existing_record_is_nil?
|
||||
@existing_record.present? && existing_value.nil?
|
||||
end
|
||||
|
||||
def create_record_in_database(options = {})
|
||||
if options[:nil_value]
|
||||
value = nil
|
||||
else
|
||||
value = 'a'
|
||||
end
|
||||
def existing_record_is_blank?
|
||||
@existing_record.present? && existing_value.strip == ''
|
||||
end
|
||||
|
||||
def create_record_in_database(options = {})
|
||||
@original_subject.tap do |instance|
|
||||
instance.__send__("#{@attribute}=", value)
|
||||
instance.__send__("#{@attribute}=", value_for_new_record(options))
|
||||
ensure_secure_password_set(instance)
|
||||
instance.save(validate: false)
|
||||
@created_record = instance
|
||||
|
@ -276,6 +315,14 @@ module Shoulda
|
|||
end
|
||||
end
|
||||
|
||||
def value_for_new_record(options = {})
|
||||
case
|
||||
when options[:nil_value] then nil
|
||||
when options[:blank_value] then ''
|
||||
else 'a'
|
||||
end
|
||||
end
|
||||
|
||||
def has_secure_password?
|
||||
@subject.class.ancestors.map(&:to_s).include?('ActiveModel::SecurePassword::InstanceMethodsOnActivation')
|
||||
end
|
||||
|
@ -297,15 +344,16 @@ module Shoulda
|
|||
end
|
||||
end
|
||||
|
||||
def validate_everything_except_duplicate_nils?
|
||||
if @options[:allow_nil] && existing_value.nil?
|
||||
create_record_without_nil
|
||||
def validate_everything_except_duplicate_nils_or_blanks?
|
||||
if (@options[:allow_nil] && existing_value.nil?) ||
|
||||
(@options[:allow_blank] && existing_value.blank?)
|
||||
create_record_with_value
|
||||
end
|
||||
|
||||
disallows_value_of(existing_value, @expected_message)
|
||||
end
|
||||
|
||||
def create_record_without_nil
|
||||
def create_record_with_value
|
||||
@existing_record = create_record_in_database
|
||||
end
|
||||
|
||||
|
|
|
@ -418,6 +418,81 @@ describe Shoulda::Matchers::ActiveModel::ValidateUniquenessOfMatcher do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when the validation allows blank' do
|
||||
context 'when there is an existing record with a blank value' do
|
||||
it 'accepts' do
|
||||
model = model_allowing_blank
|
||||
model.create!(attribute_name => '')
|
||||
expect(model.new).to matcher.allow_blank
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there is not an an existing record with a blank value' do
|
||||
it 'still accepts' do
|
||||
expect(record_allowing_blank).to matcher.allow_blank
|
||||
end
|
||||
|
||||
it 'automatically creates a record' do
|
||||
model = model_allowing_blank
|
||||
matcher.allow_blank.matches?(model.new)
|
||||
|
||||
record_created = model.all.any? do |instance|
|
||||
instance.__send__(attribute_name).blank?
|
||||
end
|
||||
|
||||
expect(record_created).to be true
|
||||
end
|
||||
end
|
||||
|
||||
def attribute_name
|
||||
:attr
|
||||
end
|
||||
|
||||
def model_allowing_blank
|
||||
_attribute_name = attribute_name
|
||||
|
||||
define_model(:example, attribute_name => :string) do
|
||||
attr_accessible _attribute_name
|
||||
validates_uniqueness_of _attribute_name, allow_blank: true
|
||||
end
|
||||
end
|
||||
|
||||
def record_allowing_blank
|
||||
model_allowing_blank.new
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the validation does not allow blank' do
|
||||
context 'when there is an existing entry with a blank value' do
|
||||
it 'rejects' do
|
||||
model = model_disallowing_blank
|
||||
model.create!(attribute_name => '')
|
||||
expect(model.new).not_to matcher.allow_blank
|
||||
end
|
||||
end
|
||||
|
||||
it 'should not allow_blank' do
|
||||
expect(record_disallowing_blank).not_to matcher.allow_blank
|
||||
end
|
||||
|
||||
def attribute_name
|
||||
:attr
|
||||
end
|
||||
|
||||
def model_disallowing_blank
|
||||
_attribute_name = attribute_name
|
||||
|
||||
define_model(:example, attribute_name => :string) do
|
||||
attr_accessible _attribute_name
|
||||
validates_uniqueness_of _attribute_name, allow_blank: false
|
||||
end
|
||||
end
|
||||
|
||||
def record_disallowing_blank
|
||||
model_disallowing_blank.new
|
||||
end
|
||||
end
|
||||
|
||||
context "when testing that a polymorphic *_type column is one of the validation scopes" do
|
||||
it "sets that column to a meaningful value that works with other validations on the same column" do
|
||||
user_model = define_model :user
|
||||
|
|
Loading…
Reference in New Issue