(Change `validate_uniqueness_of_matcher` to give non-null columns
default values)

This sounds good in theory, but we cannot choose default values that
make sense in every single context. For instance, if the column only
accepts certain values, then a default value must be chosen which is one
of those values. There is no way we can know this. Instead of making
`validate_uniqueness_of` magical, we should insist that people
create a record that has the proper attributes with the proper values
before using `validate_uniqueness_of`.
This commit is contained in:
Elliot Winkler 2014-05-09 15:07:18 -06:00
parent 2748b75087
commit 380d18f062
3 changed files with 12 additions and 50 deletions

13
NEWS.md
View File

@ -1,12 +1,21 @@
# HEAD
* Revert change to `validate_uniqueness_of` made in 2.6.0 so that it no longer
provides default values for non-primary, non-nullable columns. This approach
was causing test failures because it makes the assumption that none of these
columns allow only specific values, which is not true. If you get an error
from `validate_uniqueness_of`, your best bet continues to be creating a record
manually and calling `validate_uniqueness_of` on that instead.
# 2.6.1 # 2.6.1
## Features ### Features
* Teach `with_message` qualifier on `allow_value` to accept a hash of i18n * Teach `with_message` qualifier on `allow_value` to accept a hash of i18n
interpolation values: interpolation values:
`allow_value('foo').for(:attr).with_message(:greater_than, values: { count: 20 })`. `allow_value('foo').for(:attr).with_message(:greater_than, values: { count: 20 })`.
## Bug fixes ### Bug fixes
* Revert changes to `validate_numericality_of` made in the last release, which * Revert changes to `validate_numericality_of` made in the last release, which
made it so that comparison qualifiers specified on the validation are tested made it so that comparison qualifiers specified on the validation are tested

View File

@ -115,11 +115,6 @@ module Shoulda # :nodoc:
@subject.class.new.tap do |instance| @subject.class.new.tap do |instance|
instance.__send__("#{@attribute}=", value) instance.__send__("#{@attribute}=", value)
other_non_nullable_columns.each do |non_nullable_column|
instance.__send__("#{non_nullable_column.name}=", correct_type_for_column(non_nullable_column))
end
if has_secure_password? if has_secure_password?
instance.password = 'password' instance.password = 'password'
instance.password_confirmation = 'password' instance.password_confirmation = 'password'
@ -203,7 +198,7 @@ module Shoulda # :nodoc:
end end
def correct_type_for_column(column) def correct_type_for_column(column)
if column.type == :string || column.type == :binary if column.type == :string
'0' '0'
elsif column.type == :datetime elsif column.type == :datetime
DateTime.now DateTime.now
@ -225,12 +220,6 @@ module Shoulda # :nodoc:
end end
value value
end end
def other_non_nullable_columns
@subject.class.columns.select do |column|
column.name != @attribute && !column.null && !column.primary
end
end
end end
end end
end end

View File

@ -383,42 +383,6 @@ describe Shoulda::Matchers::ActiveModel::ValidateUniquenessOfMatcher do
end end
end end
context "a model with non-nullable attribute" do
context "of type" do
[:string, :text, :integer, :float, :decimal, :datetime, :timestamp, :time, :date, :binary, :boolean].each do |type|
context type do
it "does not raise an error" do
model = define_model_with_non_nullable(type)
expect { expect(model).to matcher }.not_to raise_error
end
end
end
end
context "that is a primary key" do
it "does not cause duplicate entry errors by re-using default values for primary keys" do
create_table :examples, id: false do |t|
t.string :attr
t.integer :non_nullable, primary: true
end
model_class = define_model(:example, attr: :string) do
validates_uniqueness_of :attr
end
model_1 = model_class.new
model_2 = model_class.new
expect(model_1).to matcher
expect { expect(model_2).to matcher }.not_to raise_error
end
end
def define_model_with_non_nullable(type)
define_model(:example, attr: :string, non_nullable: { type: type, options: { null: false } }) do
attr_accessible :attr, :non_nullable
validates_uniqueness_of :attr
end.new
end
end
def case_sensitive_validation_with_existing_value(attr_type) def case_sensitive_validation_with_existing_value(attr_type)
model = define_model(:example, attr: attr_type) do model = define_model(:example, attr: attr_type) do
attr_accessible :attr attr_accessible :attr