Reputation: 13
I have a typical User model (username, password, name, etc). I want to allow users to attach three chosen categories to their account. Each of the three categories exist in the Category model.
How can I link three foreign keys from Category to a single User without using an intermediate table for tracking? Each Category can belong to any number of Users, but each user can have only three Categories.
I played with has_many :through but I really don't think a relationship table is necessary and it would generate a lot of coding on my end to work with it.
Any ideas?
Upvotes: 1
Views: 556
Reputation: 10866
HABTM is your best bet. To restrict users to three categories, add a model level validation:
class User < ActiveRecord::Base
has_and_belongs_to_many :categories
validate :no_more_than_three_categories
protected
def no_more_than_three_categories
self.errors.add(:categories, "may not have more than three") if categories.size > 3
end
end
At your discretion, pull out the magic number 3 to a class level constant or a configuration setting.
And don't fear the code. Do it right and the code will fear you.
Upvotes: 2
Reputation: 19241
From a code maintainability standpoint, even though you may want to restrict the number of categories a user can pick to 3 right now, you may not want to code it with this limitation. You'll be kicking yourself later when you want to increase it to 5 or reduce it to 1. My suggestion would be to just use has_and_belongs_to_many
with a join table (you don't need :through
because, from what I can tell, you don't need a join model, just a join table). Using HABTM will automatically use a join table so you don't have to worry about writing the code to handle that. Just make sure you name the join table and its columns properly.
As for actually restricting the user to only 3 categories, just implement that restriction in the view/controller (i.e. restrict the UI so they can't choose more than 3).
I'm sure you've already read this, but in case you haven't, here's the docs for HABTM.
Upvotes: 2