Rails validations with accepts_nested_attributes_for and _destroy

I was recently working on a Rails app that has a form with a parent item and child items on the same form. Ryan Bates’ complex form examples is a good place to start with this. That code will give you a simple form setup with some Javascript for adding and removing rows of children.

It works pretty well, except that in my case, I needed to ensure that each parent had a minimum of one child. I had a validation which checked for this, but it only worked for creating new records. If I removed all the child rows during an edit, the form would still save successfully. It turns out that the key is in the Rails documentation: “Note that the model will not be destroyed until the parent is saved.” So my validation was still happily finding a child row, even though it was set to be deleted. It took me some time before I found the right way to check for this, but the marked_for_destruction? method seems to do the trick. Here’s my code:

class Project < ActiveRecord::Base
  has_many :tasks
  accepts_nested_attributes_for :tasks, :reject_if => :all_blank,
    :allow_destroy => true

  def validate
    # require a minimum of one task
    undestroyed_task_count = 0

    tasks.each { |t| undestroyed_task_count += 1 unless t.marked_for_destruction? }

    if undestroyed_task_count < 1
      errors.add_to_base 'There must be at least one task'

Hope this helps someone!