Reputation: 1888
I have a polymorphic association (contact_details
) in my Company model and I want to validate the parent model. Note: I am using accepts_nested_attributes_for in my parent model.
The basic rule:
the company must have at least one phone (phone is the kind of contact_detail)
The problem:
accepts_nested_attributes_for call destroy for child objects AFTER validation of the parent object
so the user are able to delete a phone. Of course, later, when the user will try to edit a company without a phone, he/she will get an error (The company must have at least one phone
).
Company (Parent) model:
class Company < ActiveRecord::Base
PHONES_NUMBER_MIN = 1
attr_accessible :name, :contact_details_attributes, ...
has_many :contact_details, :as => :contactable, :dependent => :destroy
validate do |company|
check_phones_number
end
accepts_nested_attributes_for :contact_details, :allow_destroy => true, :reject_if => :all_blank
private
def phones_number_valid?
kind = ContactDetail::Kind.phone
phones = contact_details.select { |cd| cd.kind_id == kind.id }
phones.size >= PHONES_NUMBER_MIN
end
def check_phones_number
unless phones_number_valid?
errors.add(:base, :phones_too_short, :count => PHONES_NUMBER_MIN)
end
end
...
end
ContactDetail (Child) model:
class ContactDetail < ActiveRecord::Base
attr_accessible :kind_id, :kind_value_source
belongs_to :contactable, :polymorphic => true
belongs_to :kind
validates :kind_value_source, :presence => true, :length => {:maximum => 255}
...
end
Note: I simplified the original version, so objective was clear to you. Here is the gist with the code. By using the reject_if option I am able to forbid the deletion of all the phones. It is probably the best option by now. But I want to hear your opinions.
I also found this question and tried to apply the answer, but it didn't helped a lot. The same problem, as I described above. I've drawn a flowchart so you can see the trace, as I see it.
How can I validate the parent model in such a case?
I would be grateful for any help.
Upvotes: 2
Views: 540
Reputation: 7344
From the question you referenced, you can get rid of the reject_if
and modify the line in phones_number_valid?
:
phones = contact_details.select { |cd| cd.kind_id == kind.id && !cd.marked_for_destruction? }
Upvotes: 3