验证相关对象的最大数量

Tho*_*son 6 validation activerecord ruby-on-rails

我有一个帐户模型和一个用户模型:

class Account < ActiveRecord::Base
  has_many :users
end

class User < ActiveRecord::Base
  belongs_to :account
end
Run Code Online (Sandbox Code Playgroud)

用户属于某个帐户,并且帐户具有用户最大值(每个帐户不同).但是,如何在向帐户添加新用户时验证是否未达到此最大值?

首先,我尝试在用户上添加验证:

class User < ActiveRecord::Base
  belongs_to :account
  validate :validate_max_users_have_not_been_reached

  def validate_max_users_have_not_been_reached
    return unless account_id_changed? # nothing to validate
    errors.add_to_base("can not be added to this account since its user maximum have been reached") unless account.users.count < account.maximum_amount_of_users
  end
end
Run Code Online (Sandbox Code Playgroud)

但这只有在我一次添加一个用户时才有效.

如果我通过@account.update_attributes(:users_attributes => ...)它添加多个用户,即使只有一个用户的空间,也可以直接通过.

更新:

只是为了澄清:当前验证方法验证account.users.count小于account.maximum_amount_of_users.例如,比如说account.users.count是9并且account.maximum_amount_of_users是10,那么验证将通过,因为9 <10.

问题是,在account.users.count所有用户都写入数据库之前,返回的计数不会增加.这意味着同时添加多个用户将通过验证,因为用户计数将一直相同,直到它们全部经过验证.

正如askegg指出的那样,我是否应该在帐户模型中添加验证?那怎么办呢?

rya*_*anb 16

如果您调用account.users.size而不是account.users.count它,还将包括已构建但未保存到数据库的用户.

但是,这并不能完全解决您的问题.当您呼叫account用户时,它不会返回@account指向的同一帐户实例,因此它不知道新用户.我相信这将在Rails 3中"修复",但与此同时我可以想到几个解决方案.

如果您在添加用户的同时保存帐户(我在调用时假设这样update_attributes),那么验证就可以进入.

# in account.rb
def validate_max_users_have_not_been_reached
  errors.add_to_base("You cannot have more than #{maximum_amount_of_users} users on this account.") unless users.size < maximum_amount_of_users
end
Run Code Online (Sandbox Code Playgroud)

我不确定您是如何保存关联模型的,但如果帐户验证失败,则不应保存.

另一种解决方案是user.account在更新用户属性时将实例重置为self.您可以在users_attributes setter方法中执行此操作.

# in account.rb
def users_attributes=(attributes)
  #...
  user.account = self
  #...
end
Run Code Online (Sandbox Code Playgroud)

这样,用户的帐户将指向同一个帐户实例,因此account.users.size应返回金额.在这种情况下,您将在用户模型中保留验证.

这是一个棘手的问题,但希望这能给你一些如何解决它的想法.