What Is ORM and Why I Implement It
For many coders(myself included), writing in database languages can be a difficult experience, especially if they have not had as much practice with said languages. With limited knowledge, the queries we write can be rather be simple. However, the vast majority of coders have a strong foundation in an object-oriented programming language. If there were only some way we could take that strength and use it to mitigate the weakness of working with databases. Oh wait, there’s a great technique that can do that! In this post I’d like to talk about that technique, abbreviated as ORM and an example of implementing it in Ruby.
First off, I’d like to define ORM. Object-Relational Mapping is a technique for converting data between two incompatible type systems, in this case, Ruby and SQL. It will allow us to query and manipulate data from a database through an object-oriented programming language.
Normally, we would have to interact our database by writing SQL queries such as the example code above. Ruby in its base form is unable to interact with a SQL database, we can’t write commands in Ruby and expect SQL to be able to interpret them. If we used ORM, we could be coding in Ruby and interacting with the database.
How can we implement ORM?
We’re lucky to have programmers who have already created libraries that will do so for us. Often, when people reference ORM, they are referring to an ORM software or library that implements the technique. The ORM software I will be using comes in the form of a Ruby gem called ActiveRecord. ActiveRecord will help encapsulate the code needed to manipulate data so that writing in SQL isn’t necessary anymore, we instead interact with an object in Ruby to perform the task.
Here’s a link to commonly used ORM software for different languages!
Now we’ll be going over some examples of how ActiveRecord allows us to use Ruby objects to communicate with SQL without writing a single query. I’ll be showing Ruby code from a simple CLI project using a SQL database that I built with my partners. It’s an app named SHEF (Spices, Herbs, & Everything Fine) for aspiring home chefs to elevate their food through proper use of spices and herbs. They will be able to learn about seasonings, what food pairings work well, see reviews, and buy the product.
Next I’ll show some basic SQL code to create and populate a table with data.
With ActiveRecord properly installed and set up, we can use Ruby to perform the same tasks.
Here, we make a migration file under a database folder in Ruby that will create a users table with our desired columns. ActiveRecord automatically gives the table an auto-incrementing ID column, as well as user, username, and password columns with the specified attribute types. Next if we create a User Class, ActiveRecord will link the users table with User(if AR convention is followed). ActiveRecord maps it so Ruby code in User can now manipulate data in the users table!
ActiveRecord allows me to write macros to give access to instance methods of other classes such as Review or Order. Those classes are also associated with tables we created through migration files.
This is nice since Review can have instance methods to access or manipulate the table and Users will be able to interact with the data stored in the reviews table!
However, an important thing to note is these macros do not create associations between the classes. In SQL, we’d create associations by joining our tables through code such as the example below.
If we refer to the ERD from earlier, we can see what associations we’d like to make. To make these associations in Ruby, we just define them in our migration files that are used to create tables!
So here, we made sure to create foreign keys in the reviews table for the IDs from the products and users table. This is what establishes the associations because of how the tables are now connected, sort of emulating the SQL code that joined tables. This is a big distinction from the has_many and belongs_to macros which only gives access to instance methods. With the associations completed in the migrations, and the macros written in the Classes, I’d like to give one last example of a User instance method that updates the reviews table. There’ll be zero SQL queries I promise, or at least none that we can see with our own eyes!
Now we’ve finally seen some ways in which an Object Relational Mapper can make it so that we only write in an OOP language, but still interact with multiple tables in a database. Next, I’d like to touch on some brief reasons why to use an ORM or stay away from them.
Pros
- We get to write in the language of our choice and comfort.
- Since it’s all in one place, it’s easier to update and reuse code.
- ActiveRecord will do a lot of things automatically for you and provides its own methods as well, read its documentation to get a better grasp of its functionality.
- If you are not as competent in SQL or query languages as you are in an OOP language, you can use an ORM that molds it to a your natural style of coding and still allows for meaningful usage of databases.
Cons
- Coders with a strong background in database query language will have an advantage using query language instead of ORM.
- You have to learn the about ORM library, what it offers functionally(which is often a lot, be prepared for tons of reading), and how to properly set it up, which isn’t the most straightforward thing in the world.
- It abstracts the database so you don’t write in query languages and you may become a weaker candidate as a result of not working with SQL or other database languages frequently.
All in all, I believe ORMs can be a very helpful aid and plan to continue using them in future work. However, we should always challenge ourselves and stay hungry for new knowledge to remain competitive, so don’t skimp on practicing with query languages too! Hope you enjoyed reading the post and learned a little something. Since we like to save the best for last, here’s a picture of my kitten from a few months back :)