Reputation: 4049
In a nested form, I want the user to have the ability to create or modify all of a Parent
's Childs
at one time. So let's so the params that are passed are like this:
{"childs_attributes" => [{attribute:1}, {attribute:2}, {attribute:3}...]}
I would like a validation that says for any one Parent
, the attribute
s of all of its Childs
must be unique. In other words, in the above example, that's OK because you'd get:
Parent.childs.pluck(:attribute).uniq.length == Parent.childs.pluck(:attribute).length
However, if the params passed were like below, it'd be a violation of the validation rule:
{"childs_attributes" => [{attribute:1}, {attribute:2}, {attribute:3}...]}
So far the only solution I've come up with to do this validation is in the Controller... which I know is bad practice because we want to push this to the model.
The problem is that if in the model I have something like the below:
class Parent
validate :unique_attribute_on_child
def unique_attribute_on_child
attribute_list = self.childs.pluck(:attribute)
if attribute_list.uniq.length != attribute_list.length
errors[:base] << "Parent contains Child(s) with same Attribute"
end
end
end
That won't work because self.childs.pluck(:attribute)
won't return the attribute
passed in the current update, since the current update won't have saved yet.
I guess I could do something like an after_save
but that feels really convoluted since it's going back and reversing db commits (not to mention, the code as written below [non tested, just an example] likely leads to a circular loop if I'm not careful, since Parent validate associated children)
after_save :unique_attribute_on_child
def unique_attribute_on_child
attribute_list = self.childs.pluck(:attribute)
if attribute_list.uniq.length != attribute_list.length
self.childs.each { |c| c.update_attributes(attribute:nil) }
errors[:base] << "Parent contains Child(s) with same Attribute"
end
end
end
Other ideas?
Upvotes: 1
Views: 1110
Reputation: 1173
My first impulse is to suggest that Rails uses smart pluralization and to try using children
instead of childs
, but I think this was just the example.
I now recommend that you change your strategy. Call the validation on the children like so:
class Child < ActiveRecord::Base
belongs_to :parent
...
validates :child_attribute, uniqueness: { scope: :parent }
...
end
Upvotes: 3