2011-04-27 70 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