What is the best way of preventing the last record in a has_many collection being removed?
I have two ActiveRecord classes. A simplified view of these classes:
class Account < ActiveRecord::Base has_many :user_account_roles end class UserAccountRole < ActiveRecord::Base belongs_to :account # Has a boolean attribute called 'administrator'. end
What I'm struggling with is that I'd like to be able to apply two validation rules to this: * Ensuring that the last UserAccountRole cannot be removed. * Ensuring that the last UserAccountRole that is an administrator cannot be removed.
I'm really struggling to understand the best way of achieving this kind of structural validation. I've tried adding a before_remove callback to the association, but I don't like that this has to throw an error which would need to be caught by the controller. I'd rather this be treated as 'just another validation'.
class Account < ActiveRecord::Base has_many :user_account_roles, :before_remove => check_remove_role_ok def check_remove_relationship_ok(relationship) if self.user_account_relationships.size == 1 errors[:base] << "Cannot remove the last user from this account." raise RuntimeError, "Cannot remove the last user from this account." end end end
I don't think this makes any difference, but I'm also using accepts_nested_attributes_for.
Why not use a simple validation on Account?
class Account < ActiveRecord::Base has_many :user_account_roles validate :at_least_one_user_account_role validate :at_least_one_administrator_role private def at_least_one_user_account_role if user_account_roles.size < 1 errors.add_to_base('At least one role must be assigned.') end end def at_least_one_administrator_role if user_account_roles.none?(&:administrator?) errors.add_to_base('At least one administrator role must be assigned.') end end end
This way nothing needs to be raised, and the record won't be saved unless there's at least one role, and at least one administrator role. Thus when you re-render your edit form on error, this message will show up.