diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index b20da51..952b884 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -566,15 +566,39 @@ module ActiveRecord #:nodoc: end # A convenience wrapper for find(:first, *args). You can pass in all the - # same arguments to this method as you can to find(:first). + # same arguments to this method as you can to find(:first) If the first + # argument is an integer an array of the first n records will be returned. + # + # ==== Examples + # + # Person.first # Equivalent to Person.find(:first) + # Person.first(:conditions => [ "user_name = ?", user_name]) + # Person.first(5) # Equivalent to Person.find(:all, :limit => 5) + # Person.first(5, :conditions => [ "user_name = ?", user_name]) def first(*args) - find(:first, *args) + if args.first.kind_of?(Integer) + find(:all, (args[1] || {}).merge(:limit => args.first)) + else + find(:first, *args) + end end - # A convenience wrapper for find(:last, *args). You can pass in all the - # same arguments to this method as you can to find(:last). + # A convenience wrapper for find(:first, *args). You can pass in all the + # same arguments to this method as you can to find(:first) If the first + # argument is an integer an array of the last n records will be returned. + # + # ==== Examples + # + # Person.last # Equivalent to Person.find(:last) + # Person.last(:conditions => [ "user_name = ?", user_name]) + # Person.last(5) # Equivalent to Person.find(:all, :limit => 5, :order => 'ID desc').reverse! + # Person.last(5, :conditions => [ "user_name = ?", user_name]) def last(*args) - find(:last, *args) + if args.first.kind_of?(Integer) + find(:all, reverse_order_in_options(args[1] || {}).merge(:limit => args.first)).reverse! + else + find(:last, *args) + end end # This is an alias for find(:all). You can pass in all the same arguments to this method as you can @@ -1396,6 +1420,10 @@ module ActiveRecord #:nodoc: end def find_last(options) + find_initial(reverse_order_in_options(options)) + end + + def reverse_order_in_options(options) order = options[:order] if order @@ -1408,8 +1436,7 @@ module ActiveRecord #:nodoc: scoped_order = reverse_sql_order(scope(:find, :order)) scoped_methods.select { |s| s[:find].update(:order => scoped_order) } end - - find_initial(options.merge({ :order => order })) + options.merge({ :order => order }) end def reverse_sql_order(order_query) diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index 83043c2..1fbae87 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -121,7 +121,9 @@ module ActiveRecord end def first(*args) - if args.first.kind_of?(Integer) || (@found && !args.first.kind_of?(Hash)) + if args.first.kind_of?(Integer) && !@found + find(:all, (args[1] || {}).merge(:limit => args.first)) + elsif args.first.kind_of?(Integer) || (@found && !args.first.kind_of?(Hash)) proxy_found.first(*args) else find(:first, *args) @@ -129,7 +131,9 @@ module ActiveRecord end def last(*args) - if args.first.kind_of?(Integer) || (@found && !args.first.kind_of?(Hash)) + if args.first.kind_of?(Integer) && !@found + find(:all, reverse_order_in_options({:order => proxy_options.delete(:order)}.merge(args[1] || {})).merge(:limit => args.first)).reverse! + elsif args.first.kind_of?(Integer) || (@found && !args.first.kind_of?(Hash)) proxy_found.last(*args) else find(:last, *args) diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index aebcca6..1dde5bf 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -1718,6 +1718,12 @@ class BasicsTest < ActiveRecord::TestCase def test_last assert_equal Developer.find(:first, :order => 'id desc'), Developer.last + assert_equal Developer.find(:all, :order => 'id desc', :limit => 2), Developer.last(2) + end + + def test_first + assert_equal Developer.find(:first, :order => 'id asc'), Developer.first + assert_equal Developer.find(:all, :order => 'id asc', :limit => 2), Developer.first(2) end def test_all_with_conditions diff --git a/activerecord/test/cases/named_scope_test.rb b/activerecord/test/cases/named_scope_test.rb index 444debd..9059d54 100644 --- a/activerecord/test/cases/named_scope_test.rb +++ b/activerecord/test/cases/named_scope_test.rb @@ -169,6 +169,19 @@ class NamedScopeTest < ActiveRecord::TestCase assert_equal Topic.base.last(2), Topic.base.to_a.last(2) end + def test_first_and_last_with_integer_uses_query_with_limit_rather_than_loading_all + assert_queries(2) do + base = Topic.base + base.first(2) + base.first(3) + end + assert_queries(2) do + base = Topic.base + base.last(2) + base.last(3) + end + end + def test_first_and_last_should_not_use_query_when_results_are_loaded topics = Topic.base topics.reload # force load