我想在事务中添加以下代码,以便在任何插入中出现错误时能够回滚。
def create
m = params[:message]
# EmailThread.transaction do #<=== is this correct?
if m[:parent_id].nil?
thread = EmailThread.new :title => m[:subject]
thread.save
else
thread = EmailThread.find m[:parent_id]
end
message = thread.messages.build :content => m[:content], :author_id => current_user.id
message.save
from = thread.participants.build :user_id => current_user.id
to = thread.participants.build :user_id => m[:to_user_id]
from.save
to.save
#end #<=== to here
render :json => {:success=>true,:message=>"Message sent"}
end
我读到在控制器中定义事务不是一个好的做法,有人能帮我解决这个问题吗?
问候
如中所述http://api.rubyonrails.org/classes/ActiveRecord/AutosaveAssociation.html,没有必要显式地将关联与其父对象分开保存。
在您的情况下,由于在控制器中创建的所有对象都是"依赖"的,因此首先使用build创建所有关联,然后最后保存父对象就足够了。这将自动保存所有从属关联。
只有当在同一操作中创建了两个或两个以上完全独立但在某种程度上相关的对象时,才需要在控制器中启动事务。我能想到的最好的例子是转账,有两个银行账户的debet和随后的credit。这两个账户并不"相连",但在很大程度上相互依赖:如果其中一个失败,另一个也应该失败。那时交易是唯一的解决方案!
我认为Danny的答案是正确的。但是,如果你无论如何都需要在控制器上执行事务,那么它不是执行事务的地方。你可以在你的模型中创建一个方法来实现这一点。
例如:
class Model < ActiveRecord::Base
def self.some_method some_params
Model.transaction do
#do your stuff
#return true if ok.
end
end
end
然后在您的控制器中:
def create
if Model.some_method #with the params you want to pass
#render success
else
#render error
end
end