Super easy collect_* extenstion for ActiveRecord arrays

Apologies if this was already posted, I sent this over the weekend via
Google groups and it never showed up. So I’m trying again. :slight_smile:

A while back I had an idea for extending Array#collect to work like the
ActiveRecord find_by_* method_missing method. I put it on the back
burner until I was showing a co-worker a bit about Ruby on Rails and
realized how convenient such a feature could be. As we all know Ruby is
such a fantastic language that it makes these sorts of things easy, and
sure enough it was a simple little hack. I thought I’d post it here in
case others might find it useful.

Here’s how collect normally works:

locations = Location.find(:all)

just_the_names_and_ids = locations.collect{|loc| [loc.id, loc.name]}
=> [[1, “New York Zone”], [2, “Los A. Zone”], [4, “Boston Zone”],
[5, “San Francisco Zone”], [6, “Development Center”]]

Here it is with the new collect_* feature:

just_the_names_and_ids = locations.collect_id_and_name
=> [[1, “New York Zone”], [2, “Los A. Zone”], [4, “Boston Zone”],
[5, “San Francisco Zone”], [6, “Development Center”]]

just_the_names = locations.collect_name
=> [[“New York Zone”], [“Los A. Zone”], [“Boston Zone”], [“San
Francisco Zone”], [“Development Center”]]

names_and_cities = locations.collect_name_and_city
=> [[“New York Zone”, “New York”], [“Los A. Zone”, “Los A.”],
[“Boston Zone”, “Boston”], [“San Francisco Zone”, “San Francisco”],
[“Development Center”, “Chicago”]]

Just like the find_by_* methods you can use any attribute name and
any additional attribute names instead of {|array| [array.x, array.y,
array.z]} etc. Of course the original way still works too.

It’s not limited to one and, so you can do as many as you want:

names_cities_and_ids = locations.collect_id_and_name_and_city

Or even:

even_more =
locations.collect_id_and_name_and_city_and_state_and_zip_code_and_relative_humidity_and_enough_already

You get the idea. :slight_smile:

Caveats are that it won’t work with included associations, you’ll need
to resort to a block for that. There’s nothing technically difficult
about adding that feature but I couldn’t think of a clean syntax for
allowing it. Any suggestions are welcome.

To add this functionality just paste the code below into environment.rb
(or include it from a .rb file in /lib). This could also be made into a
plugin. I’ll make one if anyone is interested.

class Array
def method_missing(method_id, arguments)
if match = /collect_([_a-zA-Z]\w
)/.match(method_id.to_s)
attributes = match.captures.last.split(‘and’)
self.collect{|array| attributes.collect{|attr|
array[attr.to_sym]}}
else
super
end
end
end

Full back story with other examples are at
http://dashing.com/blog/2006/12/09/super_easy_collect_for_activerecord_arrays

It also works with Arrays of hashes too.

I hope someone finds this useful.

Cheers,
John

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Johnpg wrote:

I hope someone finds this useful.

I like this alot. Any objections if I include this with my
ActiveRecord::Extensions plugin?

Zach
http://www.continuousthinking.com/are
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.3 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFFfd9qMyx0fW1d8G0RAo8YAJ4uGxI42Vqmi3q6vsUzbocRXXC77gCfXVqe
c0F08FZ/yLVWSszXAPa+bvA=
=sSdX
-----END PGP SIGNATURE-----

zdennis wrote:

I like this alot. Any objections if I include this with my ActiveRecord::Extensions plugin?

Sure, be my guest.

Cheers,
John