我有两种模式:用户和公司。它们都是从一个表单创建的,我正在使用这样的事务:
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的显式错误处理,但它没有帮助。我认为验证会引发错误以回滚事务。非常感谢任何帮助。
由于
答案 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)
您必须考虑这些情况
举个例子,如果你只有一对一的关系,可以用更优化的方式处理
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/
我相信你必须在事务循环之外使用一个开始结束块。