渲染无法在rescue_from ActiveRecord :: Rollback方法中呈现正确的模板

时间:2013-01-15 01:39:51

标签: ruby-on-rails ruby-on-rails-3 exception-handling transactions rails-activerecord

我正在构建电子商务网站的结帐页面,我有一个相当长的事务,它创建了一个新的用户模型和一个新的订单模型。我将这些模型的创建包装在一个事务中,这样如果一个模型的验证失败,另一个不会在数据库中闲逛。这是我的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]}

我很困惑为什么它试图渲染模板命令/创建和应用程序/创建而不是渲染订单/新。

是否有更好的方法可以强制事务失败,以便进行回滚?

3 个答案:

答案 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