Rails 3特殊验证

时间:2011-04-27 17:20:46

标签: ruby-on-rails ruby-on-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以上,我们将引发错误。

但在我的情况下,用户可以为朋友购买一些物品。因此用户可以使用购物车中的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?

1 个答案:

答案 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