validates_associated doesn't work on update (and i've tried :on => :update)

HI all-

I have two models, Story and Tag, and they are habtm. My goal is to show the errors for @story in a form on both new and edit. Everything works fine on new/create, but it fails on edit/update. First the models:

class Story < ActiveRecord::Base   attr_accessor :tag_string_holder #holds a CSV of tags ...   has_and_belongs_to_many :tags, :uniq=> true ...   def validate_associated_records_for_tags() end #to remove the generic "is invalid" error for tags ...   validates_associated :tags, :message => 'may consist of only letters, numbers, and underscores' ...

class Tag < ActiveRecord::Base   has_and_belongs_to_many :stories, :uniq => true, :order => "stories.created_at DESC" ...   validates_presence_of :tag   validates_format_of :tag, :with => /^[A-Za-z0-9\_]+$/, :message => 'Tags may consist of only letters, numbers, and underscores'

Ok, so here's the stories controller create method:

  def create #what you do when the new form is submitted     @story = Story.new(params[:story])     @story.user_id = current_user.id     if request.post?       begin         Story.transaction do           @story.write_tags           @story.save!           flash[:notice] = 'Story posted!'           redirect_to :action => 'index'         end       rescue ActiveRecord::RecordInvalid => e         render :action => "new"       end ...

Now, this works fine, I see the correct error on the stories form (from errors_for :story) if I put an invalid tag in.

Here's the update method:

def update     @story = current_user.stories.find(params[:story][:id])     @story.attributes = params[:story]     if request.post?       begin         Story.transaction do           @story.write_tags           @story.save!           flash[:notice] = 'Story updated!'           redirect_to :action => 'index'         end       rescue ActiveRecord::RecordInvalid => e         @story.valid?         render :action => "edit"       end ...

Now, I get no such error. I get nothing. If I go back and change the validates_associated to:

validates_associated :tags, :on => :update, :message => 'may consist of only letters, numbers, and underscores'

Still nothing.

In the console, if I mimic this behavior, by loading an existing story, creating a new tag, setting its tag to something invalid, when I add that tag to the story:

story.tags << tag (where tag is invalid)

An exception is thrown. After the exception, story has no errors, and tag does have an error.

So the question is, how do you use validates_associated with an already saved master on update?

Thanks for any help, Dino

Dino,

I would recommend looking at the write_tags method in story. The create and update cases are very different here because during create the tags can't be persisted until the story is saved and an id is generated. When a story is being updated its possible the tags are being saved and removed from memory before the story is saved. In that case the story validation would never encounter the invalid tags.

One other thing to check. Are the invalid tags actually being persisted or not? If they are then something is wrong with the validation.

Aaron

Aaron Baldwin wrote:

Dino,

I would recommend looking at the write_tags method in story. The create and update cases are very different here because during create the tags can't be persisted until the story is saved and an id is generated. When a story is being updated its possible the tags are being saved and removed from memory before the story is saved. In that case the story validation would never encounter the invalid tags.

Thanks Aaron, this is exactly what was happening. I wound up using build to create new tags and just associating existing tags, thus allowing the story validation to be reached in the event of an invalid tag. Thanks so much for your response.

Dino