【发布时间】:2011-12-30 11:36:08
【问题描述】:
我想限制关联中的项目数。我想确保用户拥有的东西不超过 X。这个问题was asked before 和解决方案在孩子中有逻辑:
提供的解决方案(针对类似问题):
class User < ActiveRecord::Base
has_many :things, :dependent => :destroy
end
class Thing <ActiveRecord::Base
belongs_to :user
validate :thing_count_within_limit, :on => :create
def thing_count_within_limit
if self.user.things(:reload).count >= 5
errors.add(:base, "Exceeded thing limit")
end
end
end
硬编码的“5”是个问题。我的限制根据父母而变化。事物的集合知道它相对于用户的限制。在我们的例子中,经理可以为每个用户调整(事物)的限制,因此用户必须限制其事物的集合。我们可以让 thing_count_within_limit 向其用户请求限制:
if self.user.things(:reload).count >= self.user.thing_limit
但是,这是来自 Thing 的大量用户自省。多次调用用户,尤其是 (:reload) 对我来说是危险信号。
对更合适解决方案的思考:
我认为has_many :things, :before_add => :limit_things 会起作用,但我们必须向stop the chain 提出一个例外。这迫使我更新 things_controller 来处理异常,而不是 if valid? 或 if save 的 rails 约定。
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。如果我必须如此努力,我可能做错了什么。
为此,我必须更新父模型、子控制器,并且我不能遵循约定?我错过了什么吗?我在滥用has_many, :before_add 吗?我使用 :before_add 查找了一个示例,但找不到任何示例。
我曾考虑将验证移至用户,但这只发生在用户保存/更新时。我没有看到使用它来停止添加事物的方法。
我更喜欢 Rails 3 的解决方案(如果这对这个问题很重要的话)。
【问题讨论】:
-
fyi 我在您的问题中将“事物”类名称更新为事物,因为如果可能,模型名称应始终为单数。
-
我还会考虑将
errors.add(:base, "Exceeded thing limit")从模型移动到控制器。你应该仍然有模型级别的方法,但我会用它来设置一个标志(比如说)或者只是从方法中返回真/假,然后在你的控制器中对其进行操作以确定是成功还是失败。我认为在模型中处理这种“状态”不适用于 MVC。让模型执行逻辑(确定有效性),然后让控制器处理控制做什么,去哪里等。 -
顺便说一句,我将您的问题标题从“如何限制 has_many 关联中的项目数量(来自父级)”更改为“防止在 has_many 关联中添加超过 5 个项目”,因为它似乎更好反映内容
-
医学博士:感谢语法更新。 更改标题: 从我不喜欢的解决方案中提取值 (5)(这似乎具有误导性),但我想它与我原来的相同。
-
添加到控制器中的错误:嗯。首先,
errors.add来自我不喜欢的解决方案。但是,我认为使用错误是适当的。验证发生在模型中,错误通常是由验证添加的。我认为您是在建议控制器应该分配 @user.errors.add(:features, "some message") 如果 save 为假?在验证期间添加错误正是我们如何让控制器确定要做什么和去哪里(在 Rails 中)。如果您希望孩子限制自己,我相信他们的回答是有效的。我没有。
标签: ruby-on-rails activerecord callback associations