2017-06-13 22 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和cart_id然後更新使用參數的licence_type列[:許可證]

我使用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 

除此之外,您應該將此數據的唯一性約束移動到數據庫中。具體的做法取決於你的數據庫。

可以保留驗證器,但將它視爲前端驗證;爲方便起見,創造更好的用戶體驗。但不要依賴它來保持數據的一致性,這就是數據庫的工作。


的代碼示例另一評論:

rescue具有任內的begin..end塊或作爲方法身體的一部分被放置。但在你的情況下,你有一個do..end塊沒有周圍begin..end,這將無法正常工作。

+0

感謝您的詳細解答,我已在我的帖子中提到我已將索引添加到我的數據庫級別。我完全同意你的看法,但是有一點讓我困擾的是,實際上我總共有4個請求來創建該訂單項,我更新了我的創建方法,使其更加清晰:首先,我檢索購物車,然後通過id找到產品以獲得它的價格),第三我檢查產品是否已經存在於購物車中,第四我保存我的記錄 – medBo

+0

我的想法是,我可以減少請求的數量爲3甚至更少,所以我試圖趕上'ActiveRecord: :RecordNotUnique',我發現它僅在數據庫唯一性約束失敗時觸發(而不是在模型驗證失敗時觸發),所以我想也許我可以從模型中刪除驗證,並僅依靠數據庫來引發異常我可以用'ActiveRecord :: RecordNotUnique' – medBo

+0

來捕獲它,這至少允許跳過每次檢查記錄是否存在於數據庫中的請求。但我想知道你是否有更好的想法或想法? – medBo