Thanks for choosing to read this. And I assure you that reading this blog will be fun. This blog is about my experience with an issue that I faced with Rails Association and how I got to the root cause of the issue and found a solution to it.
If you are a Rails person, you can skip the ‘Setting up the stage’ part.
Setting up the stage.
Let us get familiar with some of the terms that we are going to visit in a while.
- Rails: Ruby on Rails or simply Rails is a web development framework that works with the syntax of Ruby language. It provides an organized structure to store different files which are required for the working of a website. And Ruby makes coding easy as the syntax is nearly the same as the English language.
- Database: A database is an application used to store and retrieve data. The data will be stored in tables (rows and columns) in a database. To understand this, imagine how vessels or files are kept inside a cupboard. Inside the cupboard, you can find them on shelves. And, on the shelf, you can find them. A cupboard can be related to a database and a shelf can be related to the table.
- Association: Association is a way of saying how two tables in a database are related to each other. For example, if book and page are two tables, then their association will be “a book ‘has many’ pages”.
- Singularize and Pluralize: We all would have read singular and plural forms in English. Singularize and Pluralize are library functions in Rails that are used to convert a word from plural form to singular form and vice versa respectively.
- API Endpoint: Application Programming Interface (API) is a means through which two applications can interact and exchange data. Usually, mobile applications are developed to interact with another application called a back-end server. This back-end server will be developed with specific URLs (endpoints), using which the mobile application can interact. The back-end server can also be a website that can be accessed using internet browsers like Chrome, Firefox. For example, Facebook can be accessed using mobile applications as well as internet browsers. To understand this better, consider food delivery companies such as swiggy and zomato (which can be related to the mobile application said above). These interact with the restaurants (can be related to the back-end server) and deliver the food as per our request (can be related to mobile applications using the API endpoints of the back-end server). It is also good to notice that, we can directly go to a restaurant and have food (which can be related to the back-end server working as a website).
- Classes and Objects: Class is a programming concept that allows representing any entity as attributes and functions. The object is an instance of a class. For example, students of a school can be represented as a Student class with Name, Gender, Roll number, and such details as attributes. Listening, Speaking, Writing, and Playing can be functions of that class. Every student can be an object of the Student class.
- ORM Technique: A technique that allows access to tables and rows of a table inside a database as classes and objects respectively.
On a fine day…
I was assigned the task of creating a Rails application to serve only API endpoints, to be used for assessment purposes. A mini Social Media application popped up as an idea to develop. I was creating the tables for the application, using ORM and specifying the associations between tables. The basic table was User, containing the details of users using the application. Users post many blogs. So I created a Blog table. A user can report a blog as abuse. So I created an Abuse table with the association “a user ‘has many’ abuses” and “a blog ‘has many abuses”.
For the above tables, I had the classes User, Blog, and Abuse created in the Rails application using ORM, and the associations were specified inside the classes as given below:
The Testing Phase (where all hell breaks loose)
To test the created table classes and their associations, I created a sample User (user1), a sample Blog (blog1) as posted by the sample user. Another user (user2) was created and the sample blog (i.e.) ‘blog1’ was reported abuse (abuse1) by this new user (i.e.) ‘user2’.
The expected result using the associations on the objects created are:
But, the actual result was a real showstopper! See what happens:
Wait. What? Was class named Abuse not defined? But we had known that plural form of abuse is abuses according to English Grammar and we have defined the same.
Being faced with such a clueless error, I first searched on Google for this issue. But nothing worked out.
I contacted my technical lead and peers in my team. None of them had a clue about the issue after checking it in my machine. One day passed in despair.
The Eureka moment!
Out of no-where, I got an idea about the way associations work in Rails. In the code above, you would have noticed two types of associations, which are: ‘has_many’ and ‘belongs_to’. For belongs_to association, the target table name is mentioned in the singular form. But for has_many association, the target table name is mentioned in plural form.
Rails use the association word given (user, blogs, abuses, and blog) in the respective class to determine the target class. For example, if we give as blog1.user, Rails will look for the table using using the class User. Similarly, if we give as user1.blogs, Rails will use the singularize function and convert it to blog, after which it will look for the table blog using the class Blog.
Now I investigated the working of the singularize function with the word abuses, by giving “abuses”.singularize. As expected, the result was “abus”. The reason being bus and abuse have a similar plural form as buses and abuses respectively. So, the singularize function returned the singular form of “abuses” as “abus” and not as “abuse”.
Working towards the Solution
As this is an issue with the Rails framework, I thought of fixing it and contributing to the open-source community (on GitHub). After checking on the issues on the same topic from the past, I understood that due to older versions (Backward compatibility issue), the solution cannot be made. As an alternative, the main developer of the Rails suggested writing the solution code to a file in the application. I did the same and found the issue to have been fixed.
If you are interested in the solution, visit here. Thanks for reading this.
That’s All Folks!
This incident is a classic example to trust our intuitions while coding. It will help a lot to fix issues that we may not be aware of its root cause or solution.