This is a simplified example of what I am trying to achieve, I'm relatively new to Rails and am struggling to get my head around relationships between models.
I have two models, the User
model and the Category
model. A user can be associated with many categories. A particular category can appear in the category list for many users. If a particular category is deleted, this should be reflected in the category list for a user.
In this example:
My Categories
table contains five categories:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ID | Name | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 1 | Sports | | 2 | News | | 3 | Entertainment | | 4 | Technology | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
My Users
table contains two users:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ID | Name | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 1 | UserA | | 2 | UserB | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
UserA may choose Sports and Technology as his categories
UserB may choose News, Sports and Entertainment
The sports category is deleted, both UserA and UserB category lists reflect the deletion
I've toyed around with creating a UserCategories
table which holds the ids of both a category and user. This kind of worked, I could look up the category names but I couldn't get a cascading delete to work and the whole solution just seemed wrong.
The examples of using the belongs_to and has_many functions that I have found seem to discuss mapping a one-to-one relationship. For example, comments on a blog post.
- How do you represent this many-to-many relationship using the built-in Rails functionality?
- Is using a separate table between the two a viable solution when using Rails?
You want a
has_and_belongs_to_many
relationship. The guide does a great job of describing how this works with charts and everything:http://guides.rubyonrails.org/association_basics.html#the-has-and-belongs-to-many-association
You will end up with something like this:
Now you need to create a join table for Rails to use. Rails will not do this automatically for you. This is effectively a table with a reference to each of Categories and Users, and no primary key.
Generate a migration from the CLI like this:
Then open it up and edit it to match:
For Rails 4.0.2+ (including Rails 5.2):
Rails < 4.0.2:
With that in place, run your migrations and you can connect Categories and Users with all of the convenient accessors you're used to: