我正在构建电子商务网站的结帐页面,我有一个相当长的事务,它创建了一个新的用户模型和一个新的订单模型。我将这些模型的创建包装在一个事务中,这样如果一个模型的验证失败,另一个不会在数据库中闲逛。这是我的OrdersController中的修剪代码:
rescue_from ActiveRecord::Rollback, with: :render_new
def render_new
render action: 'new'
end
ActiveRecord::Base.transaction do
@user = User.new params[:user]
unless @user.save
raise ActiveRecord::Rollback
end
//More stuff
...
@order = Order.new params[:order]
...
unless @order.save
raise ActiveRecord::Rollback
end
end
我看到的错误是:
缺少模板订单/创建,应用/创建{:locale => [:en],:formats => [:html],:handlers => [:erb,:builder,:coffee]}
我很困惑为什么它试图渲染模板命令/创建和应用程序/创建而不是渲染订单/新。
是否有更好的方法可以强制事务失败,以便进行回滚?
答案 0 :(得分:3)
我认为将事务包装在开始/救援块中时,意图会更清晰。
def create
begin
ActiveRecord::Base.transaction do
@user = User.new params[:user]
unless @user.save
raise ActiveRecord::Rollback
end
//More stuff
...
@order = Order.new params[:order]
...
unless @order.save
raise ActiveRecord::Rollback
end
end
rescue ActiveRecord::Rollback
render action: "new" and return
end
end
你需要在create
方法中返回,否则它的执行将继续到方法的结尾,并且Rails默认渲染将发生(在这种情况下,它意味着尝试找到create.___
模板)。
如果你不喜欢开始/救援区,你可以在and return
行添加raise
raise ActiveRecord::Rollback and return
答案 1 :(得分:2)
以上答案是正确的,但渲染操作需要进行一些修改。
这样做: -
def create
is_project_saved = false
is_proposal_saved = false
ActiveRecord::Base.transaction do
is_project_saved = @project.save
is_proposal_saved = @proposal.save
if is_project_saved && is_proposal_saved
# Do nothing
else
raise ActiveRecord::Rollback
end
end
if is_project_saved && is_proposal_saved
# You can add more nested conditions as per you need.
flash[:notice] = "Proposal Created Successfully."
redirect_to project_show_path(:job_id => @project.job_id)
else
render :new
end
end
resque不会捕获ActiveRecord :: Rollback 。所以它需要在事务块之外完成。
您还可以在嵌套:requires_new => true
中使用ActiveRecord::Base.transaction
使用save_point。
答案 2 :(得分:0)
您需要提升ActiveRecord :: Rollback并根据需要管理渲染/重定向。正如@WasimKhan所说,ActiveRecord :: Rollback不会被救援抓住。
def create
@user = User.new params[:user]
ActiveRecord::Base.transaction do
if @user.save
@order = Order.new params[:order]
if @order.save
redirect_to :index
else
raise ActiveRecord::Rollback
end
else
render :new
end
end
render :new if @user.id.nil?
end