Before_save returning false does not roll back transaction

I have models with has_many and belongs_to associations. I create a
group of three interconnected records and do a save. The last record to
be saved does not pass the before_save criteria and so my before_save
function returns false. I was expecting everything to get rolled back.
But it does not. Instead, the processing of the third record quits but
the commit happens anyway – and the save returns true.

I have not pulled this out into a small stand alone example but I am
doing roughly this:

class Relationship < ActiveRecord::Base
belongs_to :link_type
belongs_to :parent, :polymorphic => true
belongs_to :child, :polymorphic => true

before_save :banana

protected

def banana
errors.add(:parent, “bogus error”)
logger.info(“returning false”)
false
end
end

class Person < ActiveRecord::Base
has_many :parents, :as => :parent, :class_name => “Relationship”
has_many :children, :as => :child, :class_name => “Relationship”
end

class Company < ActiveRecord::Base
has_many :parents, :as => :parent, :class_name => “Relationship”
has_many :children, :as => :child, :class_name => “Relationship”
end

class PeopleController < ApplicationController
def create
@person = Person.new(params[:person])

# Create optional new Company
if params[:company][:name] != "" then
  company =

Company.find_or_initialize_by_name(params[:company][:name])
link_type = LinkType.parent_to_child(“Company”, “Employee”,
“Person”)
relationship = Relationship.new(:link_type => link_type)
@person.children << relationship
relationship.parent = company
end
logger.info(“about to save”)
respond_to do |format|
if @person.save
flash[:notice] = ‘Person was successfully created.’
format.html { redirect_to person_url(@person) }
format.xml { head :created, :location => person_url(@person) }
else
format.html { render :action => “new” }
format.xml { render :xml => @person.errors.to_xml }
end
end
end
end

The log shows:


Company Create (0.000210) INSERT INTO companies (“name”,
“created_at”) VALUES(‘c25’, ‘2007-07-07 16:01:07.577598’)
SQL (0.000131) SELECT currval(‘companies_id_seq’)
before_save
link_type.child.name is Person
child_id is 23
child_type is Person
link_type.parent.name is Company
parent_id is 26
parent_type is Company
returning false
SQL (0.001573) COMMIT
Redirected to http://localhost:3000/rcm/people/23

First Person is saved, then Company is saved, then Relationship is in
the process of being saved but the before_save returns false. But, I
would expect the whole transaction to be rolled back and the save return
false. But instead it is committed and the save returns true. You can
note that we are getting redirected to people/23 not people/new

I’m doing this in before_save because at the time validate is called,
the parent_type is not filled in. It is the only place where everything
is filled in so I can actually check to make sure everything is right.
The other weird thing is validate for the relationship is being called
twice during this process. Once early on and again after person and
company has been saved. The second pass through validate has all the
fields I need but I have not figured out how to determine if this is the
first or second time through validate.

Can someone help?