开发者

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开发者_StackOverflow中文版.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.


You could place the validation on UserAccountRole. If it is the only UserAccountRole associated with the Account, then it can't be deleted.

An easier solution may be to question an underlying assumption of your design. Why have UserAccountRole be an AR backed model? Why not just make it a plain ruby class? Is the end user going to dynamically define roles? If not, then you could greatly simplify your dilemma by making it a regular ruby class.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜