This project is archived and is in readonly mode.
nested_attributes: validates_uniqueness_of fails
Reported by mo | March 7th, 2009 @ 12:36 AM | in 2.x
class Product < ActiveRecord::Base
has_many :categorizations
accepts_nested_attributes_for :categorizations
end
class Categorization < ActiveRecord::Base
belongs_to :product
belongs_to :category
validates_uniqueness_of :product_id, :scope => [:category_id]
end
If I create/edit a product and add two new (new record) "categorizations" with the same category_id, it will validate and save.
In 2.3-RC1 double new records were ignored and not saved.
Comments and changes to this ticket
-
mo March 7th, 2009 @ 01:05 AM
hmm.. this only happens with "@product.categorizations.build" in the products_controller.
I noticed something else. If I create/edit a product, choose a category and, lets say, type in an invalid product title, i get an "missing product_id" error for the chosen category.
All these bugs were not in 2.3-RC1.. that's really annoying. :/
-
Eloy Duran March 7th, 2009 @ 11:51 AM
- Assigned user set to Eloy Duran
- State changed from new to open
Could you please try to distill a failing test for the exact problem you are having? That would be greatly appreciated.
Thanks
-
Eloy Duran March 13th, 2009 @ 08:09 AM
- State changed from open to incomplete
-
Ed Lebert May 22nd, 2009 @ 02:46 PM
This is really a problem with a core rails philosophy. It assumes that, no matter what, if "valid?" returns true, then it will save successfully. That is a false presumption.
I think rails needs to completely rethink validation and incorporate database constraint detection. And it should go on the assumption that it might return true for "valid?", but not for "save". This is obviously beyond the scope of this ticket, but this is a pretty big problem.
-
oleg dashevskii July 6th, 2009 @ 08:29 AM
- Tag changed from 2.3-rc2 to 2.3.x
I've run into same problem. Test is attached.
-
bterkuile July 29th, 2009 @ 04:24 PM
I have the same problems. Shortly said: validations are not taken into account when accept_nested_attributes_for is used. I will give my problem, since I use a dirty trick on the column. I think it is not the cause, but good to add anyway: My 'short' situation:
class Employee < ActiveRecord::Base
require 'digest/sha1' attr_protected :id, :salt attr_accessor :password, :password_confirmationbelongs_to :address accepts_nested_attributes_for :address # Always have an address as employee alias :old_address :address def address
{mkd-extraction-e5528c92a92dba8e9a7c761cf9e2a0a4}end
def validate_on_create
{mkd-extraction-97fed57be83556b54a4f5d7e75b7a4a0}end ... end
When a hash containing :address_attributes => {.....} is given to Employee.new, and no password or password_confirmation, it will save => true. Without the
:address_attri butes
the validations work. -
Andrew France October 8th, 2009 @ 05:22 AM
- Tag changed from 2.3.x to nested attributes, 2.3.x, accepts_nested_attributes_for, validates_uniqueness_of
No one seems to have said this explicitly but I believe the problem is simply that validates_uniqueness_of cannot work with nested attributes because the validation only checks against saved records. I am currently handling this problem by doing an in-memory uniqueness check during the validation phase on the parent object.
-
Eloy Duran October 8th, 2009 @ 07:17 PM
@Andrew Thanks for your comment. I'm still thinking about if and how we could fix this as simple as possible, but it might also be handy for people if you could document your workaround in either the NestedAttributes or validates_uniqueness_of docs.
Care to write such a doc patch and do you think it's a valid approach?
-
Andrew France October 9th, 2009 @ 01:05 AM
Hi Eloy, I think my workaround is a bit of a kludge:
class Author has_many :books # Could easily be made a validation-style class method of course validate :validate_unique_books def validate_unique_books validate_uniqueness_of_in_memory( books, [:title, :isbn], 'Duplicate book.') end end module ActiveRecord class Base # Validate that the the objects in +collection+ are unique # when compared against all their non-blank +attrs+. If not # add +message+ to the base errors. def validate_uniqueness_of_in_memory(collection, attrs, message) hashes = collection.inject({}) do |hash, record| key = attrs.map {|a| record.send(a).to_s }.join if key.blank? || record.marked_for_destruction? key = record.object_id end hash[key] = record unless hash[key] hash end if collection.length > hashes.length self.errors.add_to_base(message) end end end end
If this is useful to people I'd be happy to tidy it up and document it somewhere, not really worth making a plugin out of it, I just put it in my initializers. It moves the validation responsibility to the parent object, which is probably bad too, but I don't think there's any way for a new instance to find out about its other unsaved instances.
Best of luck finding an elegant solution though, its got me stumped!
-
Eloy Duran January 8th, 2010 @ 02:45 PM
- State changed from incomplete to invalid
Going to close this ticket now. Though, if people keep running into this, I'd love to see Andrew's solution integrated in ActiveRecord.
-
Hervé Tatche January 8th, 2010 @ 04:14 PM
Same problem on rails (2.3.2), validates_uniqueness_of is bypassed.
-
Tamer Salama March 3rd, 2010 @ 06:45 AM
Yes! People are still running into problem. Why would the status be "invalid" if a validation is not working as it is supposed to be?
-
Eloy Duran March 3rd, 2010 @ 10:17 AM
Why would the status be "invalid" if a validation is not working as it is supposed to be?
How about reading the comments? (that's rhetorical btw.)
It works as it currently should:
“the problem is simply that validates_uniqueness_of cannot work with nested attributes because the validation only checks against saved records”
If you have a good solution/patch to your own problem, please share it with us. But your message as is, doesn't add much, sorry.
-
Piotr Mąsior April 13th, 2010 @ 08:35 AM
I run into similar BUT not SAME problem. Fully explained here: http://railsforum.com/viewtopic.php?id=38343 , I attached there quick fix, but I think it is not elegant. Basing on Eloy summary I assume that is not already any "built in" solution, to use validates_uniqueness_of at model which is used like "dictionary" in context of accepts_nested_attributes_for? I think that filter could somehow discover from what context is it fired up and then check given data against DB and decide is @new_record or not.
-
Piotr Mąsior April 13th, 2010 @ 08:37 AM
- no changes were found...
-
Roel van der Hoorn May 7th, 2010 @ 12:40 PM
Ran into exactly the same problem. Had a uniqueness constraint on a date of a ProductRate, scoped for a Product, but it wasn't validated. Andrew's patch works like a charm.
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile »
<h2 style="font-size: 14px">Tickets have moved to Github</h2>
The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>