我遇到了困难的情况。
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以上,我们将引发错误。
但在我的情况下,用户可以为朋友购买一些物品。因此用户可以使用购物车中的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: mysuperfriend@gmail.com
问题是我们需要验证两个记录的“计数字段”的总和:)
我发现的方法是在控制器中放置验证:
# 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
这是解决此问题的好方法,但这看起来很糟糕( 你能给我一些建议吗?或者也许你在这种情况下有一些exp?
答案 0 :(得分:4)
您应该能够在Cart级别而不是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
虽然这不是超级有效的,但在大多数情况下都应该有效。您甚至可以根据需要对cart_items
范围进行范围,仅对某些值执行SUM()
操作。
作为一个注释,count
是一个属性的错误名称,因为它是一个保留的SQL关键字,但它可以工作,因为ActiveRecord正确地转义它。如果您忘记在任何自定义查询中执行此操作,则可能需要特别注意它。一个好的非冲突替代方案是quantity
。