Validates :uniqueness apparently doesn't

ruby 2.0.0p0 (2013-02-24 revision 39474) [x86_64-darwin12.3.0]
Rails 3.2.13

I have a validates … :uniqueness constraint on one of the attributes
of an ActiveRecord class.

In my test suite, I set the attribute from the same attribute in a
record in the fixture. I then send invalid? to the object under test.
invalid? returns false, and the .errors object for the record shows no
errors.

A :uniqueness constraint on another attribute does invalidate the
record. All validations on other attributes behave as expected.

I’ve done what I could to search the Rails docs, Google, Stack Overflow,
and this forum for similar problems, and found nothing.

What’s wrong?

=====

All code is excerpted.

Fixture:

active_1:
name: Thomas Jefferson
tracking_code: tj_001_TC01

Class declaration:

class Family < ActiveRecord::Base
attr_accessible … :tracking_code
validates :tracking_code, :presence => true, :length => { :maximum =>
20, :minimum => 8 }, :uniqueness => true

Test case:

setup do
@copy = families(:active_1).dup
attrs = { :tracking_code => “copy01_ext”, … }
@copy.attributes = attrs
end

test “validate tracking” do
@copy.tracking_code = nil
assert @copy.invalid?, “Nil tracking code is illegal.”
# Assertion does not fire.

@copy.tracking_code = families(:active_1).tracking_code
assert @copy.tracking_code == families(:active_1).tracking_code
@copy.save  # Not sending "save" has no effect on the apparent bug
is_invalid = @copy.invalid?
assert is_invalid, "Duplicate tracking code should be invalid."
# Assertion fires
...

=====

Fritz A. wrote in post #1108098:

ruby 2.0.0p0 (2013-02-24 revision 39474) [x86_64-darwin12.3.0]
Rails 3.2.13

I have a validates … :uniqueness constraint on one of the attributes
of an ActiveRecord class.

In my test suite, I set the attribute from the same attribute in a
record in the fixture. I then send invalid? to the object under test.
invalid? returns false, and the .errors object for the record shows no
errors.

A :uniqueness constraint on another attribute does invalidate the
record. All validations on other attributes behave as expected.

I’ve done what I could to search the Rails docs, Google, Stack Overflow,
and this forum for similar problems, and found nothing.

What’s wrong?

I didn’t take the time to dig through your test code thoroughly, but
there are a few things you need to know about uniqueness validation on
ActiveRecord? The primary issue is that uniqueness is not guaranteed.
AFAIK there still exists a race condition that could cause duplicates to
be allowed in the database. This is especially true when there are
multiple instances of an app running. Or when records can be added
outside of the application.

Again, AFAIK the ONLY way to guarantee uniqueness is by using a unique
index on the column at the database level. Validation login in an ORM
(like ActiveRecord IS NOT sufficient). It is convenient to have because
it’s easier to recover from a uniqueness violation, but it does not
remove the necessity of having the unique constraint in the database.

A basic explanation of this can be found here:
http://guides.rubyonrails.org/active_record_validations_callbacks.html#uniqueness

I have a strong suspicion that your issue is related to this limitation.

On Tue, May 7, 2013 at 1:37 PM, Robert W. [email protected]
wrote:

errors.
there are a few things you need to know about uniqueness validation on
remove the necessity of having the unique constraint in the database.

A basic explanation of this can be found here:

http://guides.rubyonrails.org/active_record_validations_callbacks.html#uniqueness

I have a strong suspicion that your issue is related to this limitation.

In addition to the race condition Robert mentions, is that under test,
your database excursions might very well be wrapped in transactions
and not yet committed to the database. I suggest watching the log and
see if things are committed; unit tests generally should not rely on
the database to perform as such. Testing these sorts of things is more
an integration test where you are testing full paths back and forth.

On Tuesday, May 7, 2013 4:12:21 PM UTC+1, Ruby-Forum.com User wrote:

errors.

A :uniqueness constraint on another attribute does invalidate the
record. All validations on other attributes behave as expected.

I’ve done what I could to search the Rails docs, Google, Stack Overflow,
and this forum for similar problems, and found nothing.

What’s wrong?

The object you’re trying to edit/save is still pointing to the same row
in
the database - it’s trying to update the existing row, not create a new
row
with the same tracking code

Fred