I’ve been focusing a ton on learning regex, and the results have been rewarding. I figure if I put the same energy into data modeling, I will be equally surprised with what I learn. I’m starting back at square one with a review of basic associations in Rails.
I’ll be using two Active Record resources, bunnies and carrots, and playing around with the different ways I can express possible relationships between the two, and add complexity to them. I’ll begin by demonstrating a basic belongs_to/has_many relationship between the models.
These associations would look something like this in the database:
In the belongs_to association, each carrot is assigned to exactly one bunny. To establish ownership of each carrot, we assign the bunny_id as the foreign key in the carrots table. In our Active Record model, carrot.rb, we establish the belongs to association via the following code:
But we’re not quite finished. Relationships are a two way street. In the table above, each carrot belongs to exactly one bunny. On the flipside, each rabbit can own zero or more carrots. To express this end of the relationship we must establish a “has_many” in rabbit.rb. The code looks like this:
Notice that the name of the model after has_many is pluralized in this case, which, conveniently, sounds correct. The has_many association tells our Rails application that each rabbit object can have zero or more carrots.
But what if we want each carrot to be shared among our rabbits? How would we go about expressing that relationship in Rails—where each rabbit has many carrots and each carrot has many rabbits. There are two ways to achieve this: has_many :through and has_many_and_belongs_to. I will demonstrate the has_many: through relationship because it allows you to create a model in your application that you can refer back to. has_many :through also lets you add columns to your join table. For a discussion on both options, see the Rails documentation on Associations.
Before generating the models in rails, let’s draw out the relationship we want to create.
We want to link our two tables in a new model/join table.
In the terminal we generate our models and migrations via..
rails g model carrot color:string
rails g model bunny name:string
rails g model community carrot_id:integer bunny_id:integer
Next we must re-establish our associations between carrots and bunnies via the new community model, back in carrot.rb, bunny.rb and community.rb:
The join table/model community.rb is at the center or carrots and rabbits. community.rb binds carrots to rabbits, and rabbits to carrots. After we run our migrations, this powerful new middleman will let us use Active Record Association methods to streamline access to our data. Our migrations look like this:
We run the migrations via rake db:migrate.
So let’s open the rails console and start to examine the power of the affinity we created between bunnies and carrots. We now have access to carrots via bunnies and bunnies via carrots.
Now let’s assign another bunny to a carrot. We’ll use the method find_by to locate the bunny Hakeem in the database.
The carrot with ID #9 is now bound to two bunnies, Jasper and Hakeem. Our has_many :through association allows us to access those buns from the carrot!