views:

639

answers:

1

I am using virtual attributes to save tags in an Entry model from a comma-separated textbox in my form (based on Railscasts #167):

class Entry < ActiveRecord::Base
  has_many :entry_tags
  has_many :tags, :through => :entry_tags

  after_save :update_tags
  attr_writer :tag_names

  def tag_names
    tags.map(&:name).join(", ")
  end

  def update_tags
    if @tag_names
      self.tags = @tag_names.split(",").map do |name|
        Tag.find_or_create_by_name(name.strip)
      end
    end
  end
  private :update_tags
end

I want to add validation on my Tag names, but I'm not sure what the best way to do that would be. I have an existing validation method defined in the Tag model:

class Tag < ActiveRecord::Base
  has_many :entry_tags
  has_many :entries, :through => :entry_tags

  validates_uniqueness_of :name
  validates_format_of :name, :with => /\A[a-z0-9_ -]*\Z/, :on => :create
end

However, because the update_tags method is being called after save, any validation errors from the create would be after the Entry is already saved.

I'm thinking about creating a validation method within the Entry model and calling that on entry save, but:

  1. If I do that, I'm not sure what the best way to do the validation would be. Do I create my own validation within Entry or create a Tag object for each name and check t.valid?? Would I somehow collect validation error messages from Tag or generate them?
  2. I'm not sure if this is even the right way to do this sort of validation.

Any suggestions?

+3  A: 

If you haven't ruled it out already, I'd take a look at using validates_associated.

nakajima
I was not familiar with that, thanks for pointing it out.
Daniel Vandersluis
I tried moving my `update_tags` method to be called `before_validation`, and that worked, but it seems like the association is being validated automatically anyways when saving (I was ending up with duplicate error messages for an invalid tag).
Daniel Vandersluis