Rails Associations Part 1 : Understand the internals of Rails Associations and how has_one works
One of the first frustrations that virtually every new Rails programmer has is Rails associations system. Since most people that come into Rails were most probably previous PHP users, chances are that they have not used a similar framework before. The idea of associations is very powerful and you should definitely master its internals, because it will make your programming life so much easier and efficient. I will split my Rails posts about associations in many comprehensive parts, so that people will have a chance to better grasp the ideas behind associations and really understand what is going on. In this part, we will be discussing about has_one, which is the easiest association that you will ever create in Rails.
But, What is a Rails Association ?
Every application is about handling resources. You have a User, a Book, an Account, a Profile, a Recipe and so on. Let’s thinking about a very simple website where we have Users that can use the website and each of these users has a Profile, which holds more information about them. The first thing to notice is that a specific User and a specific Profile are very well tied together. This means that a User should always have a Profile that describes them. And this is where associations kick in. If you have created a similar application in PHP, you have designed these two models like this, in you database management system :
User ( id, name, password )
Profile( id, user_id, age, sex, location )
The Profile model specifies a foreign key, named user_id, which directly correlates a specific profile with a specific user. This exact thing is Rails’ has_one association. The difference is that Rails relies on conventions, that you need to know beforehand, in order to correctly create your models and associations. You may find this frustrating in the beginning, but you will love it as you learn more and more about the framework.
A very very important rule is never create models that end with the letter ‘s’. If you ever need a model named Status, i would suggest to redesign your approach and choose a different name, like State or so. Of course, if you really know what you are doing, you can use model that ends with an ‘s’, but if you’re just starting with Rails, by all means, avoid it. The reason that an ending ‘s’ can be a huge problem lies in Rails conventions. To make the programmer’s life easier, Rails developers have wisely thought that instead of wasting the developer’s time for specifying the same things over and over, they would take control and predefine some aspects of the framework.
One of these aspects is that every Rails Model maps to a database name, which is the plural form of the model name(inherited from ActiveRecord conventions). Therefore, if you generate a User model, you are saying to Rails that this User model instances will be saved to your database under a table named ‘users’. Rails has internal code that is able to find the plural form of your words and even detect non standard plural forms like ‘fox – foxes’ or ‘elf – elves’. Magical stuff, huh ? You now understand why an ‘s’ in the end can mess things up, so kindly avoid it.
A Rails Association DOES NOT EVER Create Database Tables
This is a misunderstanding that i’ve met in many people. When you specify a Rails association(any of them), never ever a database is automatically created for you. If not, you ask, then why do i need them ? An association is actually a way for letting Rails know that a user has a profile. This is very important because it allows you to use intuitive methods like ‘user.profile’, which grabs the profile of a specific user. But creating the database tables is a different story and is filed under Rails migrations, which we will cover in a different post.
It is, however, important, to understand how to correctly set the association between a User model and a Profile model. We know that the foreign key user_id exists in the Profile model, so we write our associations like :
class User < ActiveRecord::Base has_one :profile end class Profile < ActiveRecord::Base belongs_to :user end
This is enough for Rails to understand that each user has one profile. But what exactly is has_one and belongs_to ? Most people easily understand the self explanatory “has_one :profile” and it is the one that even newcomers always don’t have a problem with, just because it’s intuitive. Each user has_one profile, of course. But what about belongs_to ? Well, things may get a bit weird here. Why not Profile has_one User and User belongs_to Profile ? What is really the different and how do you know which one to use ?
Well, in short, belongs_to is always specified in the model where the foreign_key is set. In this case, user_id. Could we have our User model have a profile_id instead ? Well, of course we could and belongs_to would be specified in the User model then and it would work fine. However, which one sounds more natural ? A user has one profile ? Or a profile has one user ? This question pretty much explains everything. Moreover, think what will happen if a book has one user, a recipe has one user and so on. We would constantly be altering our User model to add a book_id, a recipe_id and so on. This is a bad programming practice and should be avoided. Plain english helps in database management
The Role of the Rails Generators
It is most probable that you have learned to use the Rails internal generators to create your models, which is of course, a good idea. They are the ones who create our user.rb and profile.rb model files and also generate our database migrations, which is the actual database schema. For our example, they would be like :
rails g model User name:string password:string
rails g model Profile user_id:integer age:integer sex:string location:string
Notice that ‘rails g’ is short for ‘rails generate’. After you execute the generators, they create the model files for you and your migrations. Upon executing ‘rake db:migrate’ in order to create your new database tables and inserting the has_many, belongs_to methods in your model files, you will be ready to use the association.
But, What Comforts Does the Association Provide ? Why is it that Awesome ?
Why all this hassle then ? What did you gain from doing all these things ? The answer is : premade methods. Methods that are now declared for you, and ready to be used by you. The thing is that these methods are very very powerful. You can find a list here : http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html, but let’s see some examples of that power :
(You can open up a rails console in a new project(‘rails c’ to open the console) and execute these commands yourself as well)
First get a user to use through our example :
u = User.first => User.... u.profile => nil u.create_profile(:age => 20) => Profile... u.profile => Profile...
Incredibly flexible isn’t it ? You were able to call u.profile and that returned nil because the user does not have a profile yet. So, you used ‘u.create_profile’ to create one. This create_profile method is automatically provided to you by Rails, once you set up the association, using a programming technique named Metaprogramming(more on posts to come). Then, you used u.profile to get the newly created profile. This shows some of the great power of Rails associations. There will be more posts about the other associations, stay tuned !