ActiveRecord::Base#find shortcut
Posted by Jamis on April 04, 2007 @ 10:07 AM
I use ActiveRecord::Base#find a lot in the Rails console. A lot. As a result, I’ve started doing the following:
1 2 3 |
class <<ActiveRecord::Base alias_method :[], :find end |
That little snippet saves me up to five entire keystrokes, every time I need to do a find!
1 2 3 |
prs = Person[5] prs = Person[:first] prs = Person[:all, :conditions => { :name => "Jamis" }] |
And, thanks to the existing hash and array semantics, it loses none of find’s readability for most cases. Good stuff!

1. Pete Forde said...
Wow, this is like a bucket of cold water. Except.. good cold water. I’m sure a lot of people are thinking “why didn’t I think of this?” right about now.
Are there any downsides to this? I guess I wonder why it isn’t just in core.
2. Kent Sibilev said...
I’ve been doing it for ages and I think it should be in the core.
3. badcarl said...
Elegant and intuitive, I like it.
4. Ryan Bates said...
That’s really cool! Thanks for the tip.
One thing to be aware of, this doesn’t work when doing finds through associations:
@category.products[:all, ...] # won’t work
However, calling “find” on the association will still work.
5. Joshua said...
I added a similar method directly to my User class so I could quickly look up users by id, email address or subdomain. Never thought to add it to AR directly.
6. Dave Woodward said...
Just last night, I was doing some work in the console, and I thought to myself, “I’m tired of typing User.find(..., I bet there is a way to make a shortcut, I’ll look into that later.”
Funny how you read my mind! Or maybe I read yours? Hmm…
7. Sam Smoot said...
How about:
Person5 Person.first Person.all(:name => ‘Jamis’)
Tasty! :)
8. John Topley said...
Can this go in .irbrc?
9. Jamis said...
John, sure, just make sure there’s a guard around it so it only applies when running from script/console.
I put mine in config/environment.rb, generally. That way I can use it in my code, as well as in the console.
10. Giles Bowkett said...
That’s one of those Post-It note ideas. Ten seconds after the first time you see it, you’re wondering how you ever managed to survive without it.
11. Giles Bowkett said...
Sorry for two comments in a row, I’ve just been thinking about this. I think this absolutely belongs in Rails core. Here’s why.
A lot of what Rails does turns SQL into memory management. Just like you don’t need to keep track of pointers and address space any more with garbage-collected languages, you don’t need to know SQL to write trivial Rails apps. Obviously writing a complex Rails app very often can require SQL, but SQL to some extent disappears when using Rails.
find is a method name which refers to the implementation of the method. #[] is the default collection access method name, and it’s actually much more appropriate, because it masks the implementation and refers only to the purpose of the method. #[] tells you what the method does; #find tells you how the method does it. I think #[] should be the encouraged idiom, and #find relegated to history.
12. Jamis said...
Thanks, Giles. Here’s one counter argument for why it shouldn’t be in core.
It can’t be employed without surprises. Consider: Person[5] works great, but account.people[5] doesn’t (it just returns the 5th person in the list, rather than the person with id 5). Whereas Person.find(5) and account.people.find(5) both work as expected. That disconnect cannot be resolved without breaking the array semantics of plural associations.
That’s one argument, anyway. I’m actually kind of sitting the fence on this one. It’s certainly useful; perhaps someone could throw together a (trivial) plugin for it?
13. Giles Bowkett said...
This isn’t a very strong argument, but there is the fact that Person5 is a class method and account.people5 is an instance method. So it shouldn’t be expected to do exactly the same thing anyway.
Sorry about the bold text, btw. I was trying to do the hash-mark thing for instance methods.
14. Adam Michela said...
Just last night I was yearning for this!
15. luke hartman said...
Sorry for the lapse to newbiedom, but where would you put this shortcut? In its own file? Included in every model?
16. Jamis said...
Luke, config/environment.rb is a good place for snippets like this.
17. Ryan Allen said...
I think Og uses this as its default find method and I thought it was nice… But I had no idea you could do what you’ve done with [:first, :conditions => ...]... That is unreal!
18. Michael Trier said...
Wicked cool Jamis. I’ve been annoyed by all the typing in script/console as well, but never stopped to think there could be a better way. I actually vote for pluginizing it and keeping it out of core. I think it will just complicate future feature changes, where handling this needs to always be a consideration. Nice work as always.
19. Roman LN said...
Hey Jamis. Why did you use “alias_method” instead of “alias”?
20. Giom said...
Same as Roman, I always wonder exactly what is the different between alias_method and alias.
As far as I understand ‘alias’ is not a method… But apart from that I don’t know why one would use one instead of the other.
21. Jamis said...
Mostly, I prefer
alias_methodbecause I like its syntax better than that ofalias. Otherwise,aliasandalias_methodfunction identically; if you look at the implementation ofalias_method, you’ll see it calls the same function internally asaliasdoes. Becausealiasis an actual keyword and not a method call, it is probably slight faster, if that matters to you. Beyond that, I think it’s largely a matter of taste.Oh, and note that alias_method returns the module/class that it was called for, while alias returns nil, so you could potentially chain alias_method with other method calls.
22. wilson said...
It is funny that you bring this up, Jamis. The other day as I was typing find I thought to myself, “wait, can I just use brackets here?”
The conclusion I came to was that there would be inconsistent semantics and also less uniformity Enumerable.find … which I believe is the part of Ruby that ActiveRecord::Base.find was modeled after.
In some ways it seems that AR find is moving more in the direction of taking a block as its argument… does anyone know what is coming down the pipe in the next version of Rails?
23. weepy said...
would using [] make AR slower ?
i.e. it’s an extra lookup ?
24. Jamis said...
weepy, it won’t make any significant difference. The speed of the find itself is the bottleneck, not the extra method lookup.
If you are doing tons and tons of finds in a tight loop, you could try benchmarking it to see what the difference is, but I’ll be surprised if it makes much of a blip at all.
25. Sam Smoot said...
Jamis: WRT Giles’ suggestion: There’s no need to break the semantics of #[]. If we’re duck-typing anyways. There’s no reason that a has_many needs to return an Array. It’s almost against the Ruby way. :-)
That’s what I do in the DataMapper anyways. Return a HasManyAssociation instance that’s enumerable. So account.people5 isn’t a true Array indexer, but aside from the performance hit of iterating through the loader to find the existing object with that key, there’s no database call or anything, so it’s still comparatively inexpensive since it would only be used at a high level (the application level).
weepy: Not at the application level. The most expensive loops are going to be in the object instantiation mechanisms. The methods relating to query-generation make up a small fraction of the cost in comparison. So I’d avoid it in framework internals, but at the level most people will be working at the expense is not worth thinking twice about.