Say that I have two models- Users and Accounts. Each account can have at most n users associated with it, and a user can only be associated with one account.
It would seem natural to say that User
belongs_to :account
and Account
has_many :users
However, I'm not clear on the best practice when it comes to limiting the number of associations through that has_many declaration. I know that there is a :limit argument, but that that only limits the number of associations returned, not the number that are able to exist.
I suspect that the answer is to use something like :before_add. However, that approach seems only to apply to associations created via << . So it would get called when you used
@account.users << someuser
but not if you used
@account.users.create
I had also considered that it might be more practical to implement the limit using before_save within the User model, but it seems like it would be a bit off to implement Account business rules within the User model.
What is the best practice for limiting the number of associations?
Edit: the n users per account would be some business data that is stored within the individual accounts, rather than being a straight up magic number that would be floating around willy nilly in the code.
At first, if your users table has foreign key account_id then you need to use
class User
belongs_to :account
end
In this way you will ensure that User can be associated just to one Account.
If you want to limit that Account can have e.g. at most 3 users then you can define the following validation:
class User
validates_each :account do |user, attr, value|
user.errors.add attr, "too much users for account" if user.account.users.size >= 3
end
end
and as a result you will not be able to create new user for account if account has already 3 users.
I think your rule is subject to a different interpretation. Think of the rule as being "You cannot add a user to an account that already has 3 users." Now that it is a user rule, implementing it on the user object seems perfectly natural and @Raimond's solution will suffice.
You could also think about implementing this as a database constraint, but I probably wouldn't go that way...3 seems to be an arbitrary number that may change later and I, and I suspect you, would prefer that it be captured in the code rather than hidden away in a DB constraint.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With