Rails 4 HABTM自定义关联验证 [英] Rails 4 HABTM custom validation on associations

查看:91
本文介绍了Rails 4 HABTM自定义关联验证的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的场景,但是似乎找不到适用于Rails 4的任何建议的解决方案。我只想添加一个自定义验证器,以检查我的HABTM关联之间存储的关联数量。

I've got a simple scenario, but I can't seem to find any proposed solutions that apply to Rails 4. I want to simply add a custom validator that checks the amount of stored associations between my HABTM association. Easier said and done, to my surprise?

我一直在寻找解决方案,但最终只能找到旧版本的Rails的答案。我有以下内容:

I've searched for a solution but only end up with answers for older versions of Rails it seems. I've got the following:

class User < ActiveRecord::Base

  has_and_belongs_to_many :roles
  after_save :check_maximum_number_of_roles

  .
  .
  .

  private

  def check_maximum_number_of_roles
    if self.roles.length > 3
      errors.add(:roles, 'Users can only have three roles assigned.')
      return false
    end
  end

end

class Role < ActiveRecord::Base

  has_and_belongs_to_many :users

end

我使用 after_save 的原因是,据我了解,存储关联在添加后首先可用。我也尝试编写一个自定义验证器(例如 validate::can_only_have_one_role ),但这也不起作用。

The reason I use after_save is because as far as I understand the stored association is first available after it has been added. I've also tried to write an custom validator (e.g. validate: :can_only_have_one_role), but that does not work either.

我以以下方式添加关联,并已在rails控制台中完成此操作(应该可以正常工作吗?):

I add the association in the following manner and have done this in the rails console (which should work just fine?):

user.roles << role

尽管如此,它为用户添加了多个角色,并且不关心任何类型的验证。

Nevertheless, it adds more than one role to users and does not care of any type of validation.

非常感谢,谢谢!

推荐答案

user.roles<<角色用户不执行任何验证。用户基本上不参与。所有这些操作就是在联接表中插入一条新记录。

user.roles << role performs no validation on user. The user is largely uninvolved. All this does is insert a new record into your joining table.

如果要强制用户仅具有一个角色,则有两种选择,两种选择都涉及丢弃 has_and_belongs_to_many ,您真的不应该再使用它了。 Rails提供了 has_many:through ,并且一段时间以来,这一直是进行多对多关系的首选方式。

If you want to enforce that a user has only one role, you have two options, both involve throwing away has_and_belongs_to_many, which you really shouldn't use anymore. Rails provides has_many :through, and that has been the preferred way of doing many-to-many relationship for some time.

因此,第一种方法(也是我认为最好的方法)是使用 has_many / belongs_to 。这就是您在Rails中建模一对多关系的方式。应该很简单:

So, the first (and I think best) way would be to use has_many/belongs_to. That is how you model one-to-many relationships in Rails. It should be this simple:

class Role
  has_many :users
end

class User
  belongs_to :role
end

第二种方式强制执行单个关联记录过于复杂,是创建联接模型,将其命名为 UserRole ,使用 has_many:through ,并在 UserRole 内执行验证。

The second way, which is over complex for enforcing a single associated record, is to create your joining model, call it UserRole, use a has_many :through, and perform the validation inside UserRole.

class User
  has_many :user_roles
  has_many :roles, through: :user_roles
end

class UserRole
  belongs_to :user
  belongs_to :role

  # Validate that only one role exists for each user
  validates :user_id, uniqueness: { scope: :role_id }

  # OR, to validate at most X roles are assigned to a user
  validate :at_most_3_roles, on: :create

  def at_most_3_roles
    duplicates = UserRole.where(user_id: user_id, role_id: role_id).where('id != ?', id)
    if duplicates.count > 3
      errors.add(:base, 'A user may have at most three roles')
    end
  end
end

class Role
  has_many :user_roles
  has_many :users, through: :user_roles
end

这篇关于Rails 4 HABTM自定义关联验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆