Rails事务不会在验证错误时回滚

时间:2010-02-11 16:48:23

标签: ruby-on-rails transactions

我有两种模式:用户和公司。它们都是从一个表单创建的,我正在使用这样的事务:

 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

即使公司的某个验证失败,用户也会保存到数据库中。我已经尝试添加ActiveRecord :: RecordInvalid的显式错误处理,但它没有帮助。我认为验证会引发错误以回滚事务。非常感谢任何帮助。

由于

5 个答案:

答案 0 :(得分:2)

您必须使用支持ACID事务的数据库引擎。对于是INNODB的mysql。

show table status\G

如果用户或公司使用InnoDB引擎,您可以使用此命令进行更改。

ALTER TABLE <table name> ENGINE INNODB;

@company.save! *抛出的异常应触发将ROLLBACK命令发送到数据库。您可以在运行带有DEBUG日志级别的脚本/服务器时在控制台/日志文件中对此进行验证。

答案 1 :(得分:1)

尝试保存新条目并同时修改现有条目(基于新条目),遇到了类似的问题。尝试了救援失败的交易验证,但确定了这一点:

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

代码首先验证。除非两个条目都有效,否则它不会尝试保存。事务语义防止在数据库支持的情况下对其他错误的不完整输入。希望这是一个很好的解决方案。

答案 2 :(得分:0)

您必须考虑这些情况

  1. 使用支持交易的数据库系统
  2. 重新考虑代码以获得更合理的方法
  3. 举个例子,如果你只有一对一的关系,可以用更优化的方式处理

    Company has_one User
    User belongs_to Company
    

    现在,在公司模式中

    @company.user.build(user_attributes)
    @company.save  # will save company as well as user
    

    我没有将它作为一个例子进行测试。我的想法。 我是否正确理解了问题?

答案 3 :(得分:0)

save()和destroy()总是处于事务处理之下(参见http://railsapi.com/doc/rails-v2.3.5/classes/ActiveRecord/Transactions/ClassMethods.html)。

我认为你想要做的是

  begin
    @company = Company.create!(params[:company])
    @user    = User.create!(params[:user]) { |user| user.company => @company }
  rescue => ex
    # ... handle your validation errors
  end

这将解决您的问题,因为当公司验证失败时,将引发异常并且User.create语句永远不会执行。

答案 4 :(得分:-3)

http://tempe.st/2007/05/transaction-in-rails/

我相信你必须在事务循环之外使用一个开始结束块。