Rails 4 HABTM对关联的自定义验证

Jen*_*örk 6 validation activerecord ruby-on-rails has-and-belongs-to-many ruby-on-rails-4

我有一个简单的场景,但我似乎无法找到适用于Rails 4的任何建议的解决方案.我想简单地添加一个自定义验证器来检查我的HABTM关联之间存储的关联量.更容易说和完成,令我惊讶?

我已经搜索了一个解决方案,但最终只得到了旧版本Rails的答案.我有以下内容:

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
Run Code Online (Sandbox Code Playgroud)

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

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

user.roles << role
Run Code Online (Sandbox Code Playgroud)

然而,它为用户添加了多个角色,并不关心任何类型的验证.

非常感谢,谢谢!

mea*_*gar 9

user.roles << role不执行验证user.用户基本上没有参与.所有这一切都是在您的加入表中插入一条新记录.

如果你想强制用户只有一个角色,你有两个选择,都涉及丢弃has_and_belongs_to_many,你真的不应该再使用.Rails提供了has_many :through,并且一直是做多对多关系的首选方式.

所以,第一种(我认为最好的)方式是使用has_many/ belongs_to.这就是你在Rails中建立一对多关系的方法.它应该是这么简单:

class Role
  has_many :users
end

class User
  belongs_to :role
end
Run Code Online (Sandbox Code Playgroud)

第二种方法是强制执行单个关联记录,它是创建您的连接模型,调用它UserRole,使用a has_many :through并在其中执行验证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
Run Code Online (Sandbox Code Playgroud)