Initiation by fire – part 3

1 Comment

Beginner mistake number 3:

Associations.  If you’ve worked with relational databases at all you probably know the concepts one-to-one, one-to-many, and many-to-many, and you’ve probably cried your self to sleep on a numerous occasions writing join statements that probably are longer than some children’s books.  Every Rails developers learns the basics of Rail’s model associations.

class User < ActiveRecord::Base
has_many :items
end

That little bit of code will let you automatically find all the items that have the same user_id as the users id.  Powerful stuff!  However, what most beginning developers don’t learn is the additional things that you can do with the model associations.  Find you’re doing a query to get all the user’s active items all the time?  Well why keep writing the query when you can make it an association and then call it the same way as user.items?

has_many :active_items, :class_name => 'Item', :conditions => ["status = 'Active'"]

Now you can find the user and do  user.items AND user.active_items.  This saves a ton of typing and testing, since the query is always going to be the same, you can test once and then not worry if you misspelled ‘Active’ the 30th time you wrote the query.  Also in case you’re crying foul because :class_name came out of nowhere, all it does is tell what model to use to relate it to.  Rails normally does this for you because you’re creating a relationship with the same name or pluralization of the name of the model.

Many-to-many… alright you can stop wincing now.  Yes, many to many relationships are powerful, and useful for certain situations however they make for nasty SQL statements and even nastier code implementation.  However with the has_many :through they can act just like a one-to-many relationship.

class User < ActiveRecord::Base
has_many :roles, :through => :users_roles
end

class UsersRole < ActiveRecord::Base
belongs_to :role
belongs_to :user
end

class Role < ActiveRecord::Base
has_many :users, :through => :users_roles
end

Now you can retrieve the user and get the user’s roles, or retrieve the role and get the users.  Or you can even retrieve the user and then get the user’s roles, then take one of the roles and get all of the users with that role.  Pretty neat!

The fun doesn’t stop there.  If you have a group of items linked to the user, and you don’t want orphaned items when the user decides to close up shop and delete his user account then you can even add a line to the model telling it to get rid of all the users items when the user is deleted.

has_many :items, :dependent => :destroy

If you are feeling really crazy you can even take associations one step further and write an association that uses another association.  For example you have standard association then tell your next association to go through your standard association

has_many :admin_memberships, :class_name => 'Membership', :dependent => :destroy, :conditions => ['admin = 1']
has_many :administered_groups, :through => :admin_memberships, :source => :group

Now I know I threw another curve ball in there with :source.  That, like :class_name, tells it what model to use except you use it with :through associations, once again the reason you hadn’t seen it before is because Rails is normally pretty smart about these kind of things and will attempt to use the :through value as the model unless you specify something else using :source.

Finally lets move on to what, in my opinion, is the coolest thing you can do in a model.  Polymorphic relationships, which by the way as soon as you say that to a nontechnical boss, they’ll most likely leave you alone because the word alone is enough to scare off the un-technical.  What does this association with the power to scare off bosses actually do?  Well lets say a user has multiple things associated with them that you want to dynamically load.  A picture can either be of an item or a knickknack.  Sure you could define them all as associations, but why limit yourself?  You want to find them without having to think about what you’re findign.

class Picture < ActiveRecord::Base
belongs_to :resource, :polymorphic => true, :dependent => :destroy
end

class Item < ActiveRecord::Base
has_one :picture, :as => :resource
end

class Knickknacks < ActiveRecord::Base
has_one :picture, :as => :resource
end

Now on your picture table you’d add resource_type and resource_id so they can be associated.  Now by finding a picture and calling picture.resource will return the associated item or knickknack.

However by doing all these neat associations you run into what web developers call the n+1 query problem.  You have all this power at your fingertips and you’re generating a sql query every time you try to call an associated items.  Fear not, for Ruby on Rails has already foreseen your dilemma.  Ruby on Rails has something called eager loading, which is where you can banish those nightmares you’re still having about the 5 page join statement you wrote last year.  By adding :include into your user find Rails will magically generate that giant join statement for you and load up your associations via that statement.  No fuss, no muss, you get easy to read code and you can even eager load records from your eager loading.  First lets look at the normal code.

@user = User.find(params[:id], :include => :items)

Now to find a user, load all the items, and then load the item’s picture

@user = User.find(params[:id], :include => {:items => :picture})

That will generate a giant SQL join for you and will let you call something like user.item.first.picture without even having to think about all the magical SQL that needed to be generated.

Initiation by fire – part 2

2 Comments

Beginner mistake number 2:

Names and idioms. One thing I learned about the Rails community is that all the good developers secretly wish that they were English majors and Math majors at the same time. I know it sounds silly, but Ruby devs will call you down for using a crazy model name while at the same time praise you for using a complex idiom that nobody can read unless they understand the idiom. One of my first forays into RoR development was a site called LongTimeLost (http://longtimelost.com). This is also the first site where I started working with other Rails developers and learning what is acceptable and what isn’t when building a Rails site. After a developer took one look at my code he immediately noted that ‘looking4people’ is a horrible name for a table, and at the time I couldn’t understand what he was talking about, no one but us was going to see the code, what did it matter what I named things (I admit now looking back on my choice for a table name I’m quite embarrassed). It turns out in Rails naming is important. Rails does so much magical box stuff based on what you name things, have a table called users in your database? Well the way to search it with active record is User.find. The naming also affects how easy it is to read parts of your code. Looking4Person.find really isn’t good reading and Rails above most else should be readable.

The dichotomy of Rails though, is idioms. Idioms, which can cut multiple lines of code into one line. For example, probably the most popular idiom takes this code:

if foo=’bar’
puts ‘a’
else
puts ‘b’
end

And turns it into:

puts (foo==’bar’ ? ‘a’ : ‘b’ )

Clean, elegant, and if you don’t know the idiom, you have no idea what it’s doing. Thus is the way of idioms. The best place to keep up to date on idiomatic code is http://therailsway.com/. There is no hard and fast way to learn them, mostly they come by seeing them, saying “Wow, that is cool, what does it do exactly?” and then remembering it so you can impress others later.

Naming on the other hand does have a hard and fast way to do it. For the most part imagine what you are going to name your objects in sentences and ask your self if they make sense the best ways are the associations (which I’ll write about later) and the find method.
Looking4Person.find (a good example of a bad name)
User.find (a good name)
Now with the associations:
A User has_many Relationships
A Group belongs_to Admin
A User has_many Friends through Relationships (the has_many :through will be talked about later)

Variable names also should also avoid camel case like the plague. Camel case, while the standard for languages like Java is something that will make an experienced RoR developer’s blood boil. And I’ll give you an example why, which is easier to read:
a) authenticationMethodGoesHere
b) authentication_method_goes_here
The answer is obviously b, it looks more like English and is far easier to read at a glance, which is what Rails developers love.

Initiation by fire – part 1

1 Comment

Starting off as a Rails developer I ran into some problems coming from a Java/C++ background. Until Rails I more learned the languages for fun and something to play with in my free time, however by doing this I picked up some bad habits. I’ve worked with one of the top Ruby developers out there and learned to mimic his style and question his choices in code. I’ve learned a lot in the last year and a half I’ve been coding and now am even leading up a development team and teaching them the ins and the outs of Ruby.

Beginner mistake number 1:
For loops. I’m not so sure how the books teach it now but when I was initially learning Ruby all the books showed loops as

for item in collection

This is really easy to read, and will make developers from other languages feel a little more at ease with the language (it’s got the word for in there, and everyone knows what a for loop is). However you’ll quickly learn that using those for loops is really only for beginners. The real power of the for loop in rails doesn’t even have the word for in it. The real power comes from each.

collection.each do |item|

Not only is this also easy to read but it gives you so much more control over what you are doing. Want to pass in a counter variable? Simple

collection.each_with_index do |item, counter|

Or maybe you just want to get the keys from a group of hashes.

collection.each_key do |item_key|

There are many more possibilities, and by using each you are learning the style of what is probably the most powerful module in the Ruby language the enumerable module.

Because I can't stand to be upstaged.

No Comments

I barely have time to do anything, however I can’t be upstaged by either of my colleagues, Lynn or Will (both of whom write about interesting things), I’ve decided to actually post some useful comments. As the main Ruby on Rails programmer for Powered By Geek I’ve had some interesting experiences trying to stretch the language around whatever Lynn can imagine up for me. So I’ll be talking about rails and writing tips and tricks I’ve learned similar to Lynn with web-design and Will with database administration.