2011-04-27 63 views
0

我遇到了困難的情況。Rails 3特別驗證

class Cart < ActiveRecord::Base 
    has_many :cart_items 
    accepts_nested_attributes_for :cart_items 
end 

class CartItem << ActiveRecord::Base 
    belongs_to :cart 
    belongs_to :item 

    def for_friend? 
    true if self.friend_email? 
    end 
end 

Class Item << ActiveRecord::Base 
    MAXIMUM_ITEMS_PER_USER = 10 

    has_many :cart_items 
end 

好的,這是簡單的關聯案例。每個購物車可以有很多cart_items。 但是,我們不能爲一個用戶銷售超過10件商品(換句話說,1個用戶只能購買10件綠色T恤)。此限制由定義:: Item :: MAXIMUM_ITEMS_PER_USER

驗證的最簡單的情況是每個記錄的驗證:

例如:我們有CartItem對象:

CartItem id: 1, cart_id: 1, item_id: 1, count: 1, friend_email: nil 

CartItem模型中定義的一些驗證:

class CartItem < ActiveRecord::Base 
    validates :count_per_user 
end 

def count_per_user 
    self.errors.add(:base, "ONLY 10 WE CAN") if self.count > Item::MAXIMUM_ITEMS_PER_USER 
end 

好的,如果有人設置CartItem對象數超過10個,我們會引發錯誤。

但在我的情況下,用戶可以爲朋友購買一些物品。因此,用戶可以在hes Cart中購買CartItems(區別僅在COUNT和friend_email字段中)。

它看起來像這樣:

CartItem id: 1, cart_id: 1, item_id: 1, count: 1, friend_email: nil 

CartItem id: 2, cart_id: 1, item_id: 1, count: 2, friend_email: [email protected] 

的問題是什麼,我們需要驗證的「數域」的兩個記錄:)

的方法和我找到的是放置在驗證控制器:

# controller method #update 
def update 
    @cart = Cart.find(params[:id]) 
    update_and_validate_count(params) 
end 

def update_and_validate_count(controller_params) 
    @cart_items = get_and_update_cart_items_from(controller_params) # just assign new values, but doesn't save any 
    summ = @cart_items.inject(0) {|result,r| result += r.count} 
    if summ > Item::MAXIMUM_ITEMS_PER_USER 
    @cart.errors.add(:base, "WRONG COUNT, ONLY 10 IS POSSIBLE") 
    else 
    @cart.update_attributes(controller_params[:cart]) 
    end 
end 

這是一種不錯的方法來解決這個問題,但是這是很糟糕( 你能給我一些建議也許u必須在這一些EXP?案件?

回答

4

您應該能夠在購物車層面執行此驗證,而不是CartItem。類似這樣的:

def validate_count_requirements 
    if (self.cart.cart_items.sum(:count) > Item::MAXIMUM_ITEMS_PER_USER) 
    self.errors.add(:base, "ONLY #{Item::MAXIMUM_ITEMS_PER_USER} WE CAN") 
    end 
end 

雖然這不是超高效,但它應該在大多數情況下工作。您甚至可以根據需要僅對某些值執行SUM()操作來確定cart_items的範圍。

作爲說明,count是屬性的錯誤名稱,因爲它是一個保留的SQL關鍵字,儘管它可以工作,因爲ActiveRecord會正確轉義它。如果您在任何自定義查詢中忘記執行此操作,則可能需要特別注意。一個好的不衝突的替代方案是quantity

+0

主要問題是cart.cart_items在模型級別的調用將從數據庫加載對象,而不是從內存:)這對於使用IdentityMap的Rails 3.1來說不是問題,但是在當前我使用rails 3.0.7 :) – vorobey 2011-04-27 21:53:44

+0

還要感謝有關「計數」的信息。我會解決這個問題。 – vorobey 2011-04-27 21:56:07

+0

'cart.cart_items'只會在你真正引用它作爲一個數組時加載這些項目,但是如果你在它上面調用'sum'就可以生成一個查詢。 ActiveRecord可以用這種方式偷偷摸摸。看看你的查詢日誌,你會發現它沒有像你期望的那樣被加載。 – tadman 2011-04-27 22:09:14