Skip to content
This repository
Browse code

Made `first` finder consistent among database engines by adding a

default order clause (fixes #5103)
  • Loading branch information...
commit 07e5301e697d6a02ed3c079aba07c261d53c1846 1 parent 5603050
Marcelo Silveira authored April 26, 2012
20  activerecord/lib/active_record/relation/finder_methods.rb
@@ -60,6 +60,9 @@ def find_by!(*args)
60 60
       where(*args).first!
61 61
     end
62 62
 
  63
+    # Find the first record (or first N records if a parameter is supplied).
  64
+    # If no order is defined it will order by primary key.
  65
+    #
63 66
     # Examples:
64 67
     #
65 68
     #   Person.first # returns the first object fetched by SELECT * FROM people
@@ -67,7 +70,15 @@ def find_by!(*args)
67 70
     #   Person.where(["user_name = :u", { :u => user_name }]).first
68 71
     #   Person.order("created_on DESC").offset(5).first
69 72
     def first(limit = nil)
70  
-      limit ? limit(limit).to_a : find_first
  73
+      if limit
  74
+        if order_values.empty? && primary_key
  75
+          order("#{quoted_table_name}.#{quoted_primary_key} ASC").limit(limit).to_a
  76
+        else
  77
+          limit(limit).to_a
  78
+        end
  79
+      else
  80
+        find_first
  81
+      end
71 82
     end
72 83
 
73 84
     # Same as +first+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record
@@ -319,7 +330,12 @@ def find_first
319 330
       if loaded?
320 331
         @records.first
321 332
       else
322  
-        @first ||= limit(1).to_a[0]
  333
+        @first ||=
  334
+          if order_values.empty? && primary_key
  335
+            order("#{quoted_table_name}.#{quoted_primary_key} ASC").limit(1).to_a[0]
  336
+          else
  337
+            limit(1).to_a[0]
  338
+          end
323 339
       end
324 340
     end
325 341
 
6  activerecord/test/cases/finder_test.rb
@@ -163,6 +163,12 @@ def test_first_bang_missing
163 163
     end
164 164
   end
165 165
 
  166
+  def test_first_have_primary_key_order_by_default
  167
+    expected = topics(:first)
  168
+    expected.touch # PostgreSQL changes the default order if no order clause is used
  169
+    assert_equal expected, Topic.first
  170
+  end
  171
+
166 172
   def test_model_class_responds_to_first_bang
167 173
     assert Topic.first!
168 174
     Topic.delete_all

0 notes on commit 07e5301

Please sign in to comment.
Something went wrong with that request. Please try again.