Metaprogramming in Rails: The Internals

January 7, 2016 - 4 minutes read

If you are a complete beginner to Rails, you will surely have been fascinated by the beauty of Rails that how it creates relations for you, how it creates a table in the database by just writing a migration for it, and similarly other things that do a lot for you but take only a few lines of code. Well, fascination does come at a price, and you will notice that there is code that doesn’t make any sense for a beginner. So, in this article, we shall try to break down that code, and explain it with an understanding of Ruby.

First, how does code for validation work in Ruby:

So you may be wondering how does it work. Well, in Ruby as well as in Rails, there is a keyword that always exists no matter where you are in your code, and that is: self . So if you are just in a class, and you write puts self , it is gonna print the value/name of the class. But as you get into an instance method, self immediately starts reflecting the current instance, so if you do puts self , it is gonna print the value of the instance.

If you load this class by requiring it in IRB console, you will see the following output.

But if you print the value of self in an instance method, you will get the following output:

So here is the summary: If you call a method inside the class definition and do not use any prefix
with it, it will be called on the self keyword.

So that makes writing validates :email, presence: true equivalent to self.validates :email, presence: true , and sure enough, you can explicitly write the keyword self , and your code will work with no errors:

Now, this makes sense. validates is simply a class method that we invoke, and pass different arguments in it.
Moving on to how does the code for migration work in Rails generically, let’s have a look at it:

Now, since create_table is being written in change that is an instance method, so we can surely write self.create_table instead of create_table , but since self refers to the current instance, so leaving off the keyword self makes more sense.

Following is how create_table has been defined in Rails:

You can also notice this thing that the first argument that it takes is table_name , and then you can pass different options like id: false that creates a table without id.

yield td if block_given? written in the definition of create_table tells us that it takes a block, and sure enough, it does.

So now, you can understand that how writing a line has_many :books works in Rails. Having this kind of core knowledge of Ruby surely helps you be more confident in writing and debugging Rails code. If you would like to have further info on how does ActiveRecord do all the magic, you can head over to the book: Metaprogramming Ruby 2: Program Like the Ruby Pros.

If there is something else you would like us to explore, let us know in comments section below, and never forget to have fun while learning!