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