Peter Marklund

Peter Marklund's Home


Rails Extension: ActiveRecord::Base.find(:last)

I'm at the Big Nerd Ranch Ruby on Rails bootcamp in a monastery outside Frankfurt right now having a great time. One of the students asked if you can say ActiveRecord::Base.find(:last), which you can't. The value of the first argument is typically :first, but you can't use :last. Just for educational purposes I decided to change that (it's probably not something I would use in production):

ActiveRecord::Base # Make sure class is loaded, which it probably is by now anyway
module ActiveRecord
  class Base
    def self.find_with_last(*args)
      if args.first == :last
        options = extract_options_from_args!(args)
        find_without_last(:first, options.merge(:order => "#{primary_key} DESC"))

    class << self # Needed because we are redefining a class method
      alias_method_chain :find, :last

I guess most interestingly this code illustrates how to alias a static method.

5 comment(s)


phil said 2008-04-02 02:59:

Hi, Nice, thanks! since 2.0 you should use options = args.extract_options! instead of options = extract_options_from_args!(args) Cheers!

Herb said 2008-01-16 11:52:

find(:first, :order => 'id DESC')

F said 2007-03-28 04:41:

Ruby is not Java!! There is no such thing as a "static method" in ruby. What you are referring to are class methods and they are very different from static methods in Java. Static methods in java are statically resolved (hence the name) and don't have a receiver (i.e. the object to which the method belongs). Methods in ruby are _never_ statically resolved, and _always_ have a receiver. It just happens that the receiver can be class object. Also, you cannot assume anything about the ordering of primary keys the way you do so your plugin basically doesn't work.

Mathias Stjernstrom said 2007-03-27 13:09:

Thats cool! But find(:first) is not a method for returning the row with lowest primary key is a method return the first row found. For example PostgreSQL moves a updated row to the end of the table (if not order is used). If you for example have a Page model with 3 rows # select * from pages; ID, Title ----------------- 1 Page 1 2 Page 2 3 Page 3 Page.find(:first).id => 1 Will generate this query "SELECT * FROM pages LIMIT 1" And returning 1 But if you update page 1's title p = Page.find(:first) p.title = 'Page 1 upd' Page.find(:first).id => 2 # select * from pages; ID, Title ----------------- 2 Page 2 3 Page 3 1 Page 1 upd I think :first should be renamed to :one Anyhow cool post and it does illustrates how to alias a static method :-) Cheers!

Dr Nic said 2007-03-26 13:08:

I was thinking about this API just the other day, cool. If you want part 2 of the challenge (that is, where I stopped thinking about it :) make :last work for where an :order option is passed in. Again, very cool.