Rails 4 HABTM custom validation on associations

心不动则不痛 提交于 2019-12-04 05:32:51
meagar

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.

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.

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

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
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!