Object Relational Mapping in ‘Ruby on Rails’
The term ‘active record pattern’ was coined by Martin Fowler in his 2003 book Patterns of Enterprise Application Architecture. Fowler himself succinctly describes an active record pattern as being “an object that wraps a row in a database table or view, encapsulates the database access, and adds domain logic on that data.”. This approach to database management, defined by the joining of object instances with corresponding tables, has become a staple of Object Relational Mapping with Object-Orientated (OO). Through the use of active record patterns, OO languages are able to easily interface with the databases inherent to domain specific programming languages such as SQL; a task that heretofore required a great deal of effort to allow such disparate languages to communicate. In particular, the ActiveRecord macros found within ‘Ruby on Rails’ have become a ubiquitous solution for allowing the OO language of Ruby to create, maintain, and updating SQL databases. In order to take a closer look at how ActiveRecord macros are able to update SQL databases, it is important to first understand how associations are formed in Ruby through the OO paradigm of inheritance, as well as the steps involved with saving the instances of our models to a database. As we will see, ActiveRecord is a metaprogramming tool which will take care of much of this leg-work for us, so that we may spend more time focusing on logic, and less time setting up our models and tables to accommodate the data in what ever way is desired.
Want to read this story later? Save it in Journal.
One of the main features associated with OO programming languages is the use of blank templates, in the form of ‘classes’, to generate new instances of itself. An object’s functionality is determined by the methods which are defined within that object’s class. The flexibility of object-orientated programming languages comes from their ability to utilize data associated with a separate object-class. In OO programming languages, this association can easily be established through the mechanism of inheritance. Inheritance allows for an independent Super-Class to pass on its behaviors to a dependent Sub-Class. Each of the Sub-Classes ‘inherit’ all of the methods defined in the Super-Class, while maintaining its own unique characteristics through instance methods defined specifically within the scope of the Sub-Class. It is possible to have multiple Sub-Classes which have their characteristics derived from the Super-Class, yet are each present unique behaviors in their own right.
class SuperClass attr_accessor :attribute ...end
Here we have established a Ruby class: SuperClass. It is possible to associate any sub-class to our SuperClass with the
< operator. Once associated, the sub-class will inherit all the characteristics of the super-class through the methods defined in the super-class. In this case, the methods established by Ruby’s
attr_accessor macro will allow each sub-class to inherit the instance method
#attribute. This is done through a simple association that we can declare for any sub-class, as follows:
class SubClass < SuperClass attr_accessor :attribute ...end
Having established an association to our super-class, we can now use any instance method defined within our super-class. This is, however, only a part of the equation when it comes to interfacing with SQL tables. It is nice that we have objects which inherit characteristics from a single source of truth, thus providing unity among the data derived from such relations, but we are still unable to actually apply that to our SQL tables. In order to be able to not only establish class-objects associations, but also be able to store that data in a database, we will need a mechanism for Object Relational Mapping (ORM)— which we will find within the ‘Ruby on Rails’ metaprogramming tool; ActiveRecord.
ActiveRecord allows us relay data associated with our Ruby class instances to a SQL database, where the information can be called on, updated, or deleted later on. ActiveRecord is the primary ORM tool associated with the web application framework know as ‘Ruby on Rails’. ActiveRecord allows for our Ruby Class-Models to save data associated with their instances by mapping their class names to SQL tables, and their various attributes to the columns of these tables.
Without ActiveRecord, it would be necessary to first manually establish a connection to our database, then use an ORM method within each of our Ruby class files in order to map class instances to the database. Given our previous SubClass example, this would looks something like this:
class SubClass < SuperClass attr_accessor :attribute ... def self.create_table
sql = <<-SQL
CREATE TABLE IF NOT EXISTS subclasses (
id INTEGER PRIMARY KEY,
In combination with establishing the Class inheritance associations, this can be a time consuming process. Since it is a standardized procedure that we may need to apply across multiple Class-Models, the Ruby Gem team developed the ActiveRecord gem as a way of automatically setting up these associations, and mapping those associations to our database.
Once we have loaded the ActiveRecord gem, and established our connection to the database by running
ActiveRecord::Base.establish_connection, we are able to connect our sub-class to our ActiveRecord:Base by making use of the
< operator. To continue with our SubClass example, establishing the inheritance with our ActiveRecord super-class is as simple as follow:
class SubClass < ActiveRecord::Base...end
Now that our SubClass is inheriting all of the methods associated with our
ActiveRecord::Base model, we are able to easily declare associations with other Class-Models by making use of our ActiveRecord
belongs_to macro calls. Once associations are declared, we can likewise draw instance methods associated with the separate Class-Models called by the macros. Notably, it is not the macros which are directly responsible for establishing the associations themselves. Rather, the macros are simply a metaprogramming tool that allows ActiveRecord to pattern match with the previously stated technique for establishing associations. Simply put, the
belongs_to macros are class methods native to ActiveRecord, which give us instance methods that are defined within our various Class-Models.
Consider the example above. Here we have a three model ERD (Entity Relationship Diagram) which will allow many Students to associate with many Courses, through the joiner class Grade. Through the use of ‘migration files’ ActiveRecord will be able to generate SQL tables which will be named after our Class-Models, and have columns named for the attributes (bulleted below each of our entities) along with their respective datatypes. In particular, it is important to observe that our Joiner-Class,
Grade, has within it the attributes of
course_id. This will not only allow for our
Grade class to keep track of which student instance is associated with which course instance, but will also ensure that we maintain a single source of truth when adding instances to our database. The Joiner-Class will ensure that all instances “know” about each other, and does not present compile contradictory data into our database. To implement the
has_many macros, we will need to update our Class-Models in the following way (given that what we were previously referring to as Sub-Class are now the named Class-Models Student, Grade, and Course to demonstrate a many-to-many relationship):
class Grades < ActiveRecord::Base belongs_to :student
endclass Course < ActiveRecord::Base has_many :grades
has_many :students, through: :grade
endclass Student < ActiveRecord::Base has_many :grades
has_many :courses, through: :grade
Having declared our class associations through the use of ActiveRecord macros, it is now a good time to set up our SQL tables through the use of Rails generated migration files. We can use our migration files to finalize the structure of our database’s tables, and finally begin to create and save new instances of our Class-Models to the database.
📝 Save this story in Journal.