Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

This project is archived and is in readonly mode.

Add limit functionality to find first and last

#3565

The convenience methods .first and .last on ActiveRecord::Base have had me itching to pass in an integer limit as you can with Array#first and #last. E.g.,

array = [1, 2, "buckle", :my, Shoe]
array.first    # => 1
array.first(2) # => [1, 2]
array.first(1) # => [1]
array.last(2)  # => [:my, Shoe]

Attached is a patch that adds this functionality.

Person.first    # => #<Person id: 1>
Person.first(2) # => [#<Person id: 1>, #<Person id: 2>]
Person.first(1) # => [#<Person id: 1>]
Person.last(2)  # => [#<Person id: 49>, #<Person id: 50>]

Considerations:

ActiveRecord::Base subclasses are not kinds of Array, but named scopes and association proxies come closer. Consider the following:

>> Person.scoped({}).first    # SELECT * FROM `people` LIMIT 1
=> #<Person>
>> Person.scoped({}).first(2) # SELECT * FROM `people`
=> [#<Person>, #<Person>]

The first gets special treatment. The second does not. In order to make the second consistent, it only makes sense to add the behavior to ActiveRecord::Base as well. (Named scope functionality requires additions to this patch, but I'd prefer a consensus before making any more changes.)

Additionally, it made the most sense to add logic through to @ActiveRecord.find_initial@, rather than merely to the convenience, surface methods, but this obviously could cause problems for those who have been blindly passing options hashes to find(:first) and :last that include a :limit. I'm open to the idea of a less-invasive approach that merely adds the functionality to the convenience methods, but this seemed less desirable and messier.

If this is of interest to others, it could also be added to ActiveResource::Base.

Reported by Stephen Celis · December 12th, 2009 @ 04:42 PM

State: open
Milestone: none
Assigned to: nobody
Importance: Low

Activity

  1. Stephen Celis
    Stephen Celis
    • Tag changed from activerecord, finder, find_first, find_last, limit to activerecord, finder, find_first, find_last, limit, patch

    December 12th, 2009 @ 04:44 PM

  2. Stephen Celis
  3. Ryan Bigg
    Ryan Bigg
    • Tag cleared.
    • Importance changed from to Low

    Automatic cleanup of spam.

    October 11th, 2010 @ 12:09 PM

  4. Anil Wadghule
    Anil Wadghule

    Automatic cleanup of spam.

    October 12th, 2010 @ 09:10 AM

  5. Aditya Sanghi
    Aditya Sanghi

    Automatic cleanup of spam.

    October 12th, 2010 @ 10:10 AM

  6. Aditya Sanghi
    Aditya Sanghi

    Automatic cleanup of spam.

    October 12th, 2010 @ 10:13 AM

  7. Aditya Sanghi
    Aditya Sanghi
    • State changed from new to resolved

    @Stephen, this functionality is now already in place in Rails 3.0.0. Marking this ticket as resolved. Feel free to comment, if you think otherwise.

    October 13th, 2010 @ 06:13 PM

  8. Stephen Celis
    Stephen Celis

    Does not appear to be in place in 3.0.0:

    % rails c
    Loading development environment (Rails 3.0.0)
    ruby-1.9.2-p0 > User.first 2
      User Load (0.2ms)  SELECT users. FROM users
     => []
    ruby-1.9.2-p0 > User.last 2
      User Load (0.3ms)  SELECT users. FROM users
     => []
    

    October 13th, 2010 @ 11:43 PM

  9. Stephen Celis
    Stephen Celis

    That is, the SQL query is not limited. Please re-open or change to a different state than "resolved."

    October 13th, 2010 @ 11:44 PM

  10. Ryan Bigg
    Ryan Bigg
    • State changed from resolved to open

    I can verify this issue exists on Rails 3.

    October 13th, 2010 @ 11:47 PM

  11. Aditya Sanghi
    Aditya Sanghi

    @stephen, patch also does not apply cleanly anymore since there has been much refactoring around ARel.

    I misread the second half of your OP and looked on the net result ( which works ) but the query does not since it does not use limit but gets all and then pick n from array.

    Feel free to submit another patch.

    October 14th, 2010 @ 06:23 AM

  12. Elad Meidar
    Elad Meidar

    Makes sense that the Rails default would fetch all and select back n accordingly, proper SQL query should be implemented on the adapter level since it involves different syntax for each DBMS.

    October 14th, 2010 @ 03:26 PM

  13. Stephen Celis
    Stephen Celis

    I'm happy to fix the patch if there's interest in getting this into Rails.

    @Elad, I'm not sure what you're saying. The Rails default for ActiveRecord::Base.first is to fetch one record from the database (with :limit => 1). As soon as you add a numeric argument, however, it fetches all, which is not what I would have expected. The only case I can think of where .first(n) would fetch all is ActiveRecord::Base.all.first(n), because .all returns an Array.

    October 15th, 2010 @ 07:58 PM

  14. Ryan Bigg
    Ryan Bigg

    Automatic cleanup of spam.

    October 19th, 2010 @ 08:33 AM

  15. Piotr Sarnacki
    Piotr Sarnacki

    I would add such functionality, anyone have anything against it?

    December 17th, 2010 @ 11:10 AM

  16. bingbing