Building a Many-to-Many Association in Rails-React App
Tags: rails, react, tailwindcss
Published: 2022-12-10 18:39:14

One of my capstone project's features was categorizing posts by topics where the user is able to create topics, posts, and post to different topics. Also, displaying lists of posts in each topic category. To achieve this functionality, I have used Many-to-Many relationships where the topic has-many posts and the post-has-many topics through a join table topic-posts. There are various methods available when joining tables that will allow useful functionalities. In this blog, I will walk you through how I implemented this feature step by step.

The user should be able to create a post via the form below:

![post form](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ul60id4mm775cumun0p0.png)

Note that the topic is not a column in the post table, the topic has a separate model and linked to post via Many-to-Many association.

First, we have to create the tables in the database. We need a topics table, a posts table, and a topic-posts join table.

The Entity Relationship Diagram:

![entity relationship diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p5az1lwfwq8f3tpxba47.png)

A snapshot of the schema:


![schema](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l9uuw4lb17iu7wjua9dq.png)
![schema](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gnhgni2ec9x5q2qnfzc8.png)

Next, specify the has-many-through association:


![associations](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j06ah5yvufghy3utlt5o.png)
![associations](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ng38n098x4mp9dkpshj0.png)
![associations](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jnwok5y98bvh5lh6oizm.png)

Then, create the necessary actions on the join table controller:


![index and show actions](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wdsgivzax9tp9lgsm3e2.png)
![create action](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nfwp3w89wcplfl3m1gtd.png)
![private methods](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tcvavy7vhuqom8xxj4p6.png)

Similarly, the `create` action on the post-model controller should look like this: 


![create post action](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0pb82wz2djhvwi0ylco3.png)

The most important step in the `create` action of the post is that we should create the corresponding join table before saving the post to the database.

![post params](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s4crfxob8atum6i2nwh7.png)

Because of the Many-to-Many relationship, it is important to pluralize `topic_ids` and represent it with an empty array `[]`. In this case, we only need the first id index as shown in the create action above.

Now, off to the front end, to see what the `fetch POST` body sent with the request should look like:


![fetch post body](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xh6b6nkxpvk2jv7uysgj.png)

 The `Select` and `Option` tags on the form were styled using `material-tailwind/react`:


![select and option tags](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vbq1qpcj4lz4tp7qat4i.png)

Mistakes to learn from:

- Using a styling library in the front end before configuring the functionality of the backend can lead to errors that are not obvious to detect. It is recommended to first use the basic `select` and `option` tags to ensure that the styling library requirements don't interfere with tag attributes. In my case, the Material-tailwind/React library documentation stated that the value attribute of the `Option` tag should be a string whereas we need to send it as an integer to the backend.

Here is a snapshot of the documentation of the Material-tailwind/React library:


![material tailwind library docs](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4k2knq46mpzvm2tgju7g.png)

Since the value attribute datatype was an integer, interpolating the value was the way to fulfill the styling library requirements. Additionally, we should `parseInt(state value)` to make sure we are sending an integer value to the backend.

- Saving the post to the database without creating a corresponding join table was another mistake that I made that resulted in creating posts without being assigned to a specific topic category. Also, it is important to wrap `topic_ids` in a string quote due to the styling library requirements discussed above. 
Creating the join table will only be necessary depending on the functionality we are looking for. For instance, in this project, the user can create many topics and topics have many users. For this type of behavior, I did not need to create the join table `topic-users` before saving the topic to the database although the `topic-users` join model is needed for Many-to-Many associations. The difference here is that I want my post to be specifically assigned to a topic at the time of creation, whereas that is not the case when a user creates a topic; there was no emphasis on which user creates the topic.