One of my most challenging hurdles in learning rails over the past 18 months has been in understanding how to use objects from outside classes. I received some clarity in this respect that has cleared things up for me. The Rails Guides, describe this best:
Today we’ll cover the complete setup required (not including project setup), and show some illustrations. My intent is for anyone who reads this post to have an easier time understanding this than I have.
Step 1: Parent and Descendant Class Setup
Lets assume that we just created our new rails project. From here we can create two models like so:
Here we have two classes. The
User class contains attributes that allow us to store and retrieve data from our future
attr_accessible is just a rails method that specifies a white list of model attributes that can be set via mass-assignment. The second class called
Media houses the actual file in an attribute called
file and allows for the reading and writing of a few additional attributes dealing with future
The first thing we should do at this point, after having both classes created by running
rails generate model User first_name last_name city state zip in our terminal, is to select one of these classes to be the
parent of the other. By the way, if you’ve noticed that I didn’t specify the data-type for any of the attributes I listed above, its because rails defaults to the type of
string when creating attributes in the terminal. If I had added an attribute of address, my terminal command for adding an address attribute would have looked like
address:text. You can, if you’d like, continue to add
string data-types to your attributes from the command line, it may help a very new developer have a slight advantage in understanding whats going on at the step of class creation from the terminal.
Step 2: Adding
The next step towards passing objects between Rails classes or models is to name one of the associated classes the parent and the other a descendant. It makes sense to me that an object instantiated from the
User class should have many medias. Usually (I can’t think of any edge cases, but I’m sure they exist) a media file is uploaded and edited by someone. So in this case we’ll assume that future objects of the class
Media are being managed by our future
We could say it like this, a
User has_many :medias. We use the plural form of the media because its assumed that each user will have the ability to manage multiple
And since our
User class includes a
has_many :medias we place the line
belongs_to :user in our
Media. Lets see that get updated in our file of our two classes:
One thing to note about using a
has_many and a
belongs_to in our classes, is that the class that receives the
belongs_to will always contain the foreign_key of it’s parent. So in this case, we need to add
user_id to our Media class. This way whenever we write an Active Record query for a media object, we will automatically know to which
user the media object belongs to. Here’s an example from one of my projects of the schema.rb file with a foreign key inside a class’ table with a
belongs_to associated with it, I’ll keep it to two tables for brevity.
If we look at the
articles table we can see that there is not an
t.integer "id" column. This is because Rails builds in the
"id" upon migration, and is not needed by the schema.rb file. However, as we can see from the above illustration, the
Article class does have an association defined in it. That association has to be a
belongs_to :event relationship, because a foreign key has been added to this table. Remember how I said that Rails will bake in the class’
"id" field? Well when a foreign key is added, you can also tell its foreign because the class associated with it will need it’s id spelled out. Like you see in articles, there is an
event_id field. That may be a bit too much redundancy to explain the point, but its in the spirit of clarity.
The second table was shown just to briefly mention that I have two foreign keys (albeit they are from the same class). There are various methods available for the
belongs_to association I’ll attempt to illustrate what the Rails Guides says about this:
Frist for the
has_many :articles, dependent: :destroy bit.
Here’s an explanation about a method to use when you desire a custom foreign key name:
And finally an excerpt straight from the Rails guides about specifiying two foreign keys from the same class with different names:
Step 3: Time for Action!
Now that we have the setup out of the way. Lest see how we can pass an object from
First, here’s our model setup:
Note that I’ve added a
dependent: :destroy hash to the
has_many :medias association. This enables database to keep clean. When a user decides to quit our application, not only are their attribute records removed, but due to our adding
dependent: :destroy the
@user object’s associated media files will be removed as well. Making all media objects associated with a specific user dependent upon that user for their existence.
To get this data into our views, we first have to package our desired object(s) in our controller, so it can pull the correct object’s data from the database through Active Record. Here’s a quick illustration of a part of my media controller from a project I’m currently building.
If you’re interested in learning more about the
before_filter on line 2 in the above illustration, you should checkout my past post covering my first refactor: with Adam Cuppy.
So as we can see from my
index method, I have assigned the parent class or model with the
has_many :medias relationship expressed to an object that returns a list of all
@media objects. To create a new
@media object instead of
@media = media.new we can use the
build method instead.
And in any of our
Media view files, we can use the
@media instance variable to render data based upon a specific
media object’s ID (for instance, in our
show view file) or use
@medias which will return all media objects in existence.
I wanted to thank my pairing pal Russell Baker, for helping me clear up a few things about Rails associations. Its always good to run problems by an actual person, especially if you’ve done the appropriate research, and find yourself stumped.