Learning new things about Ruby on Rails every day

I have been working with Rails for over 2 years now, and still i manage to discover new stuff while crawling around the source code.
Seeing as i have missed some really cool things, i decided to share some of those small discoveries with everyone else.

OrderedHash

I have seen a lot of discussion and help requests about ruby Hashes and maintaining its key order.
Well i just stumbled upon the implementation of an ordered hash today.
It’s namespaced inside ActiveSupport module, and it basically works just like a regular Hash, but with the additional feature of maintaining the order of keys accord to the insertion order.

hash = ActiveSupport::OrderedHash.new
hash.store(:first, 1)
hash[:second] = 2

So it pretty much works like a regular hash, although you have to use the namespaced constructor to create one.
The reason behind it is that it would’nt shadow the other implementations of OrderedHash (for example Ruby 1.9 already has feature this built in, which also means that ActiveSupport::OrderedHash then references to ::Hash).

Enumerable.group_by

I had the need to group an array of association objects by one field – that mean by abusing inject and building a new hash of items by looping through the whole collection.
And just today i accidentally stumbled upon Enumerable.group_by method. It does exactly what you would expect – it groups set elements by method/attribute.

This feature is actually already implemented in Ruby 1.8.7, but Rails core extension removes that method and replaces it with it’s own.
The reason behind it is that in Ruby’s own implementation, the results are not ordered, as in Rails’ implementation is built on top of ActiveSupport::OrderedHash.

class Order < ActiveRecord::Base
  has_many :order_items
end

# our example order_items would contain items from vendors named Eckö, Nike, Abercrombie
order_items = order.order_items.all(:order => :vendor_name)
order_items.group_by(:&vendor_name)

=> #<OrderedHash {"Abercrombie" => [#<OrderItem ..>, #<OrderItem..>], "Eckö" => [#<OrderItem...>], "Nike" => [#<OrderItem>]}>

In this example i ask for all order items, order them by vendor name and then group them up by the same column. This results in a ordered hash, where the key is the vendor name (in the order i want) with value being an array of all matching order items with that vendor.

AssociationCollection.any?

You probably have seen, or even used Array/Hash methods any? or empty?
You probably also have discovered that an association acts a lot like an array, with having both of those methods.
My personal expectation, when seeing these methods, was that when calling association.any?, it would fetch all the record from the database and then calls Array.any? on it.
As i usually do not want to load the whole association to check if there are any records in it, i then opted for doing association.count > 0 (which does a SELECT COUNT(*) etc query on the database).

And once again, crawling around the source i discovered that Rails is actually pretty clever and implements both mentioned methods on top of count queries.

order.order_items.empty?
=> "SELECT COUNT(*) FROM order_items WHERE order_id = 1"

# Snippet from AssociationCollection

def empty?
 size.zero?
end

def any?
  if block_given?
    method_missing(:any?) { |*block_args| yield(*block_args) }
  else
    !empty?
  end
end

So AssociationCollection.any? is implemented on top of AssociationCollection.empty?, which is implemented on top of AssociationCollection.size.
And by the way, AssociationCollection.size does not hit the database if the collection is already loaded, if not, it does a simple count query.

I hope this stuff will be useful for someone at some point and i will also try and share any neat discoveries with you in the future.

P.S Shoperb, our new no-hassle e-commerce solution, is shaping up really well.

Tanel Suurhans
Tanel is an experienced Software Engineer with strong background in variety of technologies. He is extremely passionate about creating high quality software and constantly explores new technologies.

4 Comments

  • Sohan

    The DrinkRails blog linked to your post.

  • Tanel Suurhans

    Thanks a lot, it’s good to know this stuff interests other fellow developers out there also.

  • George

    Didn’t know about the group_by method. This would definitely come in handy. Thanks!

Liked this post?

There’s more where that came from. Follow us on Facebook, Twitter or subscribe to our RSS feed to get all the latest posts immediately.