Ruby on rails Rails:如何限制多个关联中的项目数(来自父级)

Ruby on rails Rails:如何限制多个关联中的项目数(来自父级),ruby-on-rails,activerecord,callback,associations,Ruby On Rails,Activerecord,Callback,Associations,我想限制关联中的项目数。我想确保用户拥有的东西不超过X个。这个问题和解决方案在孩子身上具有逻辑性: 提供的解决方案(针对类似问题): 但是,这是用户对事情的很多反思。对用户的多次调用,尤其是(:reload)对我来说都是危险信号 关于更合适解决方案的想法: 我原以为有很多:东西,:before\u add=>:limit\u东西会起作用,但我们必须提出一个例外。这迫使我更新things\u控制器来处理异常,而不是rails约定的if valid?或if save class User has

我想限制关联中的项目数。我想确保用户拥有的东西不超过X个。这个问题和解决方案在孩子身上具有逻辑性:

提供的解决方案(针对类似问题): 但是,这是用户对事情的很多反思。对用户的多次调用,尤其是
(:reload)
对我来说都是危险信号

关于更合适解决方案的想法: 我原以为
有很多:东西,:before\u add=>:limit\u东西
会起作用,但我们必须提出一个例外。这迫使我更新things\u控制器来处理异常,而不是rails约定的
if valid?
if save

class User
  has_many :things, :before_add => limit_things

  private
  def limit_things
    if things.size >= thing_limit
      fail "Limited to #{thing_limit} things")
    end
  end
end
这是Rails。如果我必须这么努力,我可能做错了什么。 要做到这一点,我必须更新父模型,子模型的控制器,我不能遵循约定?我错过什么了吗?我是否误用了
有很多,:在添加之前?我使用:before_add查找了一个示例,但没有找到任何示例

我曾考虑将验证转移到用户,但这只发生在用户保存/更新时。我看不出用它来阻止添加东西的方法


我更喜欢Rails 3的解决方案(如果这对这个问题很重要的话)。

您是如何调查使用accepts\u nested\u attributes\u for的

接受\u嵌套的\u属性\u for:things,:limit=>5


也就是说,我认为接受嵌套属性似乎只适用于某些类型的情况。例如,如果您正在创建一个命令行API,我认为这是一个非常糟糕的解决方案。但是,如果您有一个嵌套表单,它工作得足够好(大多数情况下)。

您可以尝试
验证
的长度\u和
验证相关的

class Client < ActiveRecord::Base

  has_many :orders
  validates :orders, :length => { :maximum => 3 }

end

class Order < ActiveRecord::Base

  belongs_to :client
  validates_associated :client

end
class客户端{:最大=>3}
结束
类顺序
显示
有效?
方法按预期工作,但它不会阻止您添加新对象。

您应该尝试此方法

class Thing <ActiveRecord::Base
  belongs_to :user
  validate :thing_count, :on => :create

  def thing_count
      user = User.find(id)
      errors.add(:base, "Exceeded thing limit") if user.things.count >= 5
  end
end
类事物:创建
什么东西都不算
user=user.find(id)
错误。如果user.things.count>=5,则添加(:base,“超出了事物限制”)
结束
结束

所以,如果您想为每个用户设置不同的限制,您可以将things\u limit:integer添加到用户中并执行以下操作

class User
  has_many :things
  validates_each :things do |user, attr, value|
   user.errors.add attr, "too much things for user" if user.things.size > user.things_limit
  end
end

class Thing
  belongs_to :user
  validates_associated :user, :message => "You have already too much things."
end
使用此代码,您无法将user.things\u limit更新为比他已获得的所有内容都低的数字,当然,它会限制用户按其user.things\u limit创建内容

应用程序示例Rails 4:


保存完成后,验证当前计数会导致计数超过限制。我找到的防止创建发生的唯一方法是验证在创建之前,事情的数量是否小于限制

这并不是说对用户模型中的计数进行验证是没有用的,但这样做并不会阻止调用
User.things.create
,因为用户的计数集合在保存新对象之前是有效的,在保存之后变得无效

class User
  has_many :things
end

class Thing
  belongs_to :user
  validate :on => :create do
    if user && user.things.length >= thing_limit
      errors.add(:user, :too_many_things)
    end
  end
end

rails4
中,您可能只需在
计数器缓存的值上进行验证即可

class User
  has_many :things
  validates :things_count, numericality: { less_than: 5 }
end

class Thing
  belongs_to :user, counter_cache: true
  validates_associated :user
end
请注意,我使用了
:小于
,因为
:小于或等于
将允许
事物计数
6
,因为它是在计数器缓存更新后验证的

如果要基于每个用户设置限制,可以创建一个
things\u limit
列,以便与您设置的限制值进行动态比较

validates :things_count, numericality: { less_than: :things_limit }

试试这个,就像字符串一样:

class User < ActiveRecord::Base
  has_many :things, :dependent => :destroy
  validates :things, length: {maximum: 4}
end
class用户:毁灭
验证:things,长度:{最大值:4}
结束

我想我应该在这里插话。看起来这里的大多数答案在比赛条件下都失败了。我试图限制在我们的应用程序中以某个价位注册的用户数量。检查Rails中的限制意味着10个同时注册可以通过,即使它超过了我试图设置的限制

例如,假设我想限制注册不超过10次。假设我已经注册了5个用户。假设有6个新用户试图同时注册。在6个不同的线程中,Rails读取剩余插槽的数量,并得到答案
5
。这通过了验证。Rails允许所有注册通过,我有11个注册:/

下面是我如何解决这个问题的:

def reserve_slot(price_point)
  num_updated = PricePoint.where(id: price_point.id)
    .where('num_remaining <= max_enrollments')
    .update_all('num_remaining = num_remaining + 1')

  if num_updated == 0
    raise ActiveRecord::Rollback
  end
end
def reserve_插槽(价格点)
num\u updated=PricePoint.where(id:price\u point.id)

在哪里(NUMFORY FYI FI我把您的问题中的“类”名称更新为模型名称,如果可能的话,总是应该是单数的。我也会考虑移动<代码>错误。从模型到控制器添加((基,“超过的东西限制”)< /代码>。您仍然应该有模型级别的方法,但是我会用它来设置一个标志(比如说)。或者只是从方法中返回true/false,然后在控制器中对其进行操作,以确定是成功还是失败。我认为在模型中处理这种“状态”对MVC不起作用。让模型执行逻辑(确定有效性)但是,让控制员处理如何做、去哪里等的控制。顺便说一句,我将您的问题标题从“如何限制has________________________________________因为它似乎更好地反映了内容M.D.:感谢语法更新。更改标题:这会从我不喜欢的解决方案中提取值(5)(这似乎有误导性),但我想它与我原来的值相同。添加到控制器中的错误:嗯。首先,class User < ActiveRecord::Base has_many :things, :dependent => :destroy validates :things, length: {maximum: 4} end
def reserve_slot(price_point)
  num_updated = PricePoint.where(id: price_point.id)
    .where('num_remaining <= max_enrollments')
    .update_all('num_remaining = num_remaining + 1')

  if num_updated == 0
    raise ActiveRecord::Rollback
  end
end