Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails transaction doesn't rollback on validation error

I have two models: user and company. They both get created from one form and I'm using a transaction like this:

 User.transaction do

  @user.save!

  @company.user = @user
  @company.save!

  @user.reload
  @user.company = @company
  @user.save!

 flash[:notice] = "Thank you for your registration."
  redirect_to_index
end

The user gets saved to the database even when one of the company's validations fails. I've tried adding explicit error handling of ActiveRecord::RecordInvalid but it didn't help. I thought the validation would raise the error to rollback the transaction anyway. Any help is greatly appreciated.

Thanks

like image 816
Shagymoe Avatar asked Feb 11 '10 16:02

Shagymoe


2 Answers

You must use a database engine that supports ACID transactions. For mysql that is INNODB.

show table status\G

If users or companies is not using InnoDB engine, you can change it w/ this command.

ALTER TABLE <table name> ENGINE INNODB;

the exception thrown from @company.save! *should trigger a ROLLBACK command to be sent to the database. you can verify this in the console/logfile when running script/server with DEBUG log level.

like image 183
Kevin Avatar answered Sep 22 '22 17:09

Kevin


attempting to save a new entry and revise an existing entry (based on the new entry) at the same time, ran into a similar problem. Tried transaction with rescue failed validation, but settled on this instead:

if @new_entry.valid? && @existing_entry.valid?
  ActiveRecord::Base.transaction do
    @new_entry.save!
    @existing_entry.save!
  end
end

the code validates first. it doesn't attempt to save unless both entries are valid. transaction semantics guard against incomplete entry on other errors if the database supports it. hope that's a good solution.

like image 34
Douglas Lovell Avatar answered Sep 19 '22 17:09

Douglas Lovell