From d5a4d5abb41c50f96b554374b937ffe49d472d7f Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Wed, 12 Mar 2008 21:26:02 +0000 Subject: Added ActiveRecord::Base.find(:last) (closes #11338) [miloops] git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@9012 5ecf4fe2-1ee6-0310-87b1-e25e094e27de --- activerecord/lib/active_record/base.rb | 39 +++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index d5da9408f3..a30036f561 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -430,12 +430,14 @@ module ActiveRecord #:nodoc: @@schema_format = :ruby class << self # Class methods - # Find operates with three different retrieval approaches: + # Find operates with four different retrieval approaches: # # * Find by id: This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]). # If no record can be found for all of the listed ids, then RecordNotFound will be raised. # * Find first: This will return the first record matched by the options used. These options can either be specific # conditions or merely an order. If no record can be matched, nil is returned. + # * Find last: This will return the last record matched by the options used. These options can either be specific + # conditions or merely an order. If no record can be matched, nil is returned. # * Find all: This will return all the records matched by the options used. If no records are found, an empty array is returned. # # All approaches accept an options hash as their last parameter. The options are: @@ -475,6 +477,11 @@ module ActiveRecord #:nodoc: # Person.find(:first, :conditions => [ "user_name = ?", user_name]) # Person.find(:first, :order => "created_on DESC", :offset => 5) # + # Examples for find last: + # Person.find(:last) # returns the last object fetched by SELECT * FROM people + # Person.find(:last, :conditions => [ "user_name = ?", user_name]) + # Person.find(:last, :order => "created_on DESC", :offset => 5) + # # Examples for find all: # Person.find(:all) # returns an array of objects for all the rows fetched by SELECT * FROM people # Person.find(:all, :conditions => [ "category IN (?)", categories], :limit => 50) @@ -499,6 +506,7 @@ module ActiveRecord #:nodoc: case args.first when :first then find_initial(options) + when :last then find_last(options) when :all then find_every(options) else find_from_ids(args, options) end @@ -1236,6 +1244,35 @@ module ActiveRecord #:nodoc: find_every(options).first end + def find_last(options) + order = options[:order] + + if order + order = reverse_sql_order(order) + elsif !scoped?(:find, :order) + order = "#{table_name}.#{primary_key} DESC" + end + + if scoped?(:find, :order) + 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 })) + end + + def reverse_sql_order(order_query) + reversed_query = order_query.split(/,/).each { |s| + if s.match(/\s(asc|ASC)$/) + s.gsub!(/\s(asc|ASC)$/, ' DESC') + elsif s.match(/\s(desc|DESC)$/) + s.gsub!(/\s(desc|DESC)$/, ' ASC') + elsif !s.match(/\s(asc|ASC|desc|DESC)$/) + s.concat(' DESC') + end + }.join(',') + end + def find_every(options) include_associations = merge_includes(scope(:find, :include), options[:include]) -- cgit v1.2.3