【问题标题】:Validate max amount af associated objects验证关联对象的最大数量
【发布时间】:2026-01-23 04:15:01
【问题描述】:

我有一个 Account 模型和一个 User 模型:

class Account < ActiveRecord::Base
  has_many :users
end

class User < ActiveRecord::Base
  belongs_to :account
end

用户属于一个帐户,一个帐户有一个用户上限(每个帐户不同)。但是,在向帐户添加新用户时,如何验证尚未达到此最大值?

首先我尝试对用户添加验证:

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

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

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

更新:

澄清一下:当前的验证方法验证account.users.count 小于account.maximum_amount_of_users。比如说account.users.count 是 9,account.maximum_amount_of_users 是 10,那么验证就会通过,因为 9

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

所以正如 askegg 指出的那样,我是否也应该向 Account 模型添加验证?那应该怎么做呢?

【问题讨论】:

    标签: ruby-on-rails validation activerecord


    【解决方案1】:

    如果您调用 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
    

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

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

    # in account.rb
    def users_attributes=(attributes)
      #...
      user.account = self
      #...
    end
    

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

    这是一个棘手的问题,但希望这能给您一些解决方法的想法。

    【讨论】:

    • 在高吞吐量应用程序上,如何在数据库(postgres)上完成?
    【解决方案2】:

    它通过的原因是因为 update_attributes 没有通过验证。

    另外 - 您的逻辑仅根据允许的最大数量检查现有帐户数量。没有考虑尝试添加的用户数量的计算。我认为这个逻辑更属于 Account 模型(?)。

    【讨论】:

    • update_attributes 确实运行验证 - 至少在 Rails 2.3.2 中。但问题是,用户模型上的验证方法验证了与帐户上已有的用户数量相比,没有达到最大值。 IE。如果 max == 10 和 users.count == 9,那么 - 当同时添加两个用户时 - 对他们两个都运行验证,但每次验证 9
    • 啊——对不起。 Update_attribute(注意末尾缺少的“s”)绕过验证。我的错。看起来 Ryan(他的 Rubyfoo 比我多得多)已经回答了你的问题。我不知道“大小”方法包括未保存的记录。你每天都会学到一些东西:)