1

e コマース サイトのチェックアウト ページを作成しています。新しい 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

私が見ているエラーはこれです:

{:locale=>[:en]、:formats=>[:html]、:handlers=>[:erb、:builder、:coffee]} でのテンプレートの注文/作成、アプリケーション/作成の欠落

注文/新規をレンダリングする代わりに、テンプレートの注文/作成とアプリケーション/作成をレンダリングしようとする理由について混乱しています。

ロールバックが発生するようにトランザクションを強制的に失敗させるより良い方法はありますか?

4

3 に答える 3

3

トランザクションを 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.___) 。

begin/rescue ブロックが気に入らない場合はand returnraise行に を追加するだけです

raise ActiveRecord::Rollback and return
于 2013-01-15T01:48:47.570 に答える
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

ActiveRecord::Rollbackは resque によってキャッチされません。そのため、トランザクション ブロックの外で実行する必要があります。

:requires_new => trueネストされた でsave_point を使用することもできますActiveRecord::Base.transaction

于 2014-04-16T08:33:20.300 に答える
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
于 2016-03-01T19:35:01.117 に答える