melekes
melekes

Reputation: 1888

How can I validate a parent model, which uses accepts_nested_attributes_for

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. flowchart

How can I validate the parent model in such a case?

I would be grateful for any help.

Upvotes: 2

Views: 540

Answers (1)

Tanzeeb Khalili
Tanzeeb Khalili

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

Related Questions