2017-06-13 21 views
1

後、私はこのようになります私のLineItemモデルの一意性制約があります。キャッチはActiveRecord :: RecordNotUniqueおよび他のすべての例外が

class LineItem < ApplicationRecord 
    # this add uniqueness validation to [cart_id + product_id] together 
    validates :cart_id, uniqueness: { scope: [:product_id] } 
end 

を私は+一意索引を追加しました:真のためだけでなく、私のデータベースでこれらの列に私LineItemsController#create私は私がやろうとしています何

class LineItemsController < ApplicationController 

    def create 

     @cart = Cart.find(session[:cart_id] 

     product = Product.find(params[:product_id] 

     @line_item = @cart.add_product(product, params[:licence]) 

     respond_to do |format| 

      @line_item.save! 

      format.html { redirect_to products_url } 
      format.js 

     rescue ActiveRecord::RecordNotUnique 

      @cart.line_items 
      .find_by(product_id: params[:product_id]) 
      .update(licence_type: params[:licence], price: product.price) 

      format.js 

     end 

    end 

end 

を以下しているに複数のセキュリティ

は次のとおりです。ユーザーがすでに同じPRODを持つ行項目を追加する場合uct_id、その後のparamsとlicence_type列を更新cart_id [:ライセンス]

は、この目的のためにrescue ActiveRecord::RecordNotUniqueを使用しています:

1 - これはそれを行うための良い方法です(私は追加の要求という私の自己を保存することができますレコードがデータベースに存在するかどうか毎回チェックします)。

2 - ActiveRecord::RecordNotUnique以外の例外/エラーをどのようにキャッチできますか?他のすべての例外をキャッチすることができるように、別のrescue Exception => eを追加すると思いましたが、そのような一般的な例外をキャッチすると、代わりにrescue => eのようなものを使用する必要があります。

すべてのコードスニペットをいただきありがとうございます!

答えて

1

Never rely on uniqueness validation重複したデータからあなたを守ります。競争条件には十分に確立された弱点があります。

この場合、おそらく何が必要なのかはfind_or_initialize_byです。

line_item = @cart.line_items.find_or_initialize_by(product_id: params[:product_id]) 
line_item.license_type = params[:license] 
line_item.save 

さらに、このデータの一意性制約をDBに移動する必要があります。具体的なやり方は、DBの内容によって異なります。

バリデータは保持しても問題ありませんが、フロントエンドの検証のように扱います。より便利なユーザーエクスペリエンスを作り出すことができます。しかし、あなたのデータの一貫性を保つためにそれに頼るのではなく、あなたのDBの仕事です。


コードサンプルに別のコメントは:

rescuebegin..endブロック内またはメソッド本体の一部としてのいずれかで配置されなければなりません。しかしあなたの場合は、周囲にbegin..endのないブロックdo..endがありますが、これはうまくいかないでしょう。

+0

詳細な回答ありがとうございました。私は既にDBレベルにインデックスを追加しました。私はあなたに完全に同意しますが、少し気にしているのは実際には、私は4つのリクエストを合計してその広告申込情報を作成しています。私は作成方法をより明確に更新しました。最初にカートを取得し、その価格を得るために)、3番目私は、製品が既にカートに存在するかどうかを確認します.4番目に私の記録を保存します。 – medBo

+0

私の考えは、要求の数を3またはそれ以下に減らすことができたので、 'ActiveRecord: :RecordNotUnique'これは、データベースの一意性制約が失敗したときだけ(モデル検証が失敗したときではなく)トリガーされていることがわかったので、モデルから検証を削除してデータベースに依存して例外を発生させることができます私は 'ActiveRecord :: RecordNotUnique'でこれをキャッチできます – medBo

+0

これは少なくとも、レコードがデータベースに存在するかどうかを毎回チェックするリクエストをスキップできるようにします。私はあなたが良いアイデアや考えを持っているかどうかを知りたいですか? – medBo

関連する問題