ruby on rails -在rescue_from ActiveRecord::Rollback方法中渲染正确模板失



我正在为一个电子商务网站构建结帐页面,并且我有一个相当长的事务,它创建了一个新的User模型和一个新的Order模型。我将这些模型的创建封装在一个事务中,这样,如果其中一个模型的验证失败,另一个模型就不会在数据库中挂起。下面是我的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

我看到的错误是:

缺少模板orders/create, application/create with {:locale=>[:en],:formats=>[:html],:handlers=>[:erb,:builder,:coffee]}

我很困惑,为什么它试图渲染模板orders/create和application/create,而不是渲染orders/new。

是否有更好的方法来强制事务失败以便发生回滚?

我认为在begin/rescue块中包装事务的意图更清晰一些。

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.___模板)

如果您不喜欢开始/救援块,您可以在raise行中添加and return

raise ActiveRecord::Rollback and return

以上答案是正确的,但需要对渲染动作进行一些修改。

这样做:-

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

ActiveRecord::Rollback不会被request捕获。所以它需要在事务块之外完成。

您也可以在嵌套的ActiveRecord::Base.transaction中使用:requires_new => true来使用save_point

您需要引发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

相关内容

  • 没有找到相关文章

最新更新