Validating change in a has_many collection

I needed to implement a validation rule on an object which has a has_many relationship to another object. I needed to check whether the collection itself had been changed, rather than associated objects within the collection i.e. were objects added to or removed from the collection?

This was, surprisingly, not as obvious as it would seem. I make use of some rather obscure ActiveRecord associated callbacks, specifically the after_add and before_remove callbacks.

When the callbacks are triggered, I set an instance variable which allows me to easily determine if the collection has changed. I can then use this in my validation rule.

Finally, after the object is successfully saved I ensure the validation flag is reset.

class Assembly < ActiveRecord::Base
  attr_reader :parts_changed
  after_save  :clear_parts_changed

  has_many :manifests
  has_many :parts, through: :manifests,
    after_add:     :parts_changed!,
    before_remove: :parts_changed!

  validates_with Validator::Assembly

  private

  def parts_changed!(_)
    @parts_changed = true
  end

  def clear_encoding_presets_changed
    @parts_changed = false
  end
end

module Validator
  class Assembly < ActiveModel::Validator

    def validate(assembly)
      if assembly.parts_changed
        # handle the validation failure
        # ...
        # ...
      end
    end

  end
end
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s