Skip to content

Commit

Permalink
Introducing take as a replacement to the old behavior of first
Browse files Browse the repository at this point in the history
  • Loading branch information
mhfs committed May 3, 2012
1 parent 489166e commit 1379375
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 3 deletions.
2 changes: 1 addition & 1 deletion activerecord/lib/active_record/querying.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

module ActiveRecord
module Querying
delegate :find, :first, :first!, :last, :last!, :all, :exists?, :any?, :many?, :to => :scoped
delegate :find, :take, :take!, :first, :first!, :last, :last!, :all, :exists?, :any?, :many?, :to => :scoped
delegate :first_or_create, :first_or_create!, :first_or_initialize, :to => :scoped
delegate :find_by, :find_by!, :to => :scoped
delegate :destroy, :destroy_all, :delete, :delete_all, :update, :update_all, :to => :scoped
Expand Down
27 changes: 27 additions & 0 deletions activerecord/lib/active_record/relation/finder_methods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,25 @@ def find_by!(*args)
where(*args).first!
end

# Gives a record (or N records if a parameter is supplied) without any implied
# order. The order will depend on the database implementation.
# If an order is supplied it will be respected.
#
# Examples:
#
# Person.take # returns an object fetched by SELECT * FROM people
# Person.take(5) # returns 5 objects fetched by SELECT * FROM people LIMIT 5
# Person.where(["name LIKE '%?'", name]).take
def take(limit = nil)
limit ? limit(limit).to_a : find_take
end

# Same as +take+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record
# is found. Note that <tt>take!</tt> accepts no arguments.
def take!
take or raise RecordNotFound
end

# Find the first record (or first N records if a parameter is supplied).
# If no order is defined it will order by primary key.
#
Expand Down Expand Up @@ -329,6 +348,14 @@ def find_some(ids)
end
end

def find_take
if loaded?
@records.take(1)[0]
else
@take ||= limit(1).to_a[0]
end
end

def find_first
if loaded?
@records.first
Expand Down
26 changes: 24 additions & 2 deletions activerecord/test/cases/finder_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,26 @@ def test_find_by_sql_with_sti_on_joined_table
assert_equal [Account], accounts.collect(&:class).uniq
end

def test_take
assert_equal topics(:first), Topic.take
end

def test_take_failing
assert_nil Topic.where("title = 'This title does not exist'").take
end

def test_take_bang_present
assert_nothing_raised do
assert_equal topics(:second), Topic.where("title = 'The Second Topic of the day'").take!
end
end

def test_take_bang_missing
assert_raises ActiveRecord::RecordNotFound do
Topic.where("title = 'This title does not exist'").take!
end
end

def test_first
assert_equal topics(:second).title, Topic.where("title = 'The Second Topic of the day'").first.title
end
Expand Down Expand Up @@ -197,7 +217,8 @@ def test_model_class_responds_to_last_bang
end
end

def test_first_and_last_with_integer_should_use_sql_limit
def test_take_and_first_and_last_with_integer_should_use_sql_limit
assert_sql(/LIMIT 3|ROWNUM <= 3/) { Topic.take(3).entries }
assert_sql(/LIMIT 2|ROWNUM <= 2/) { Topic.first(2).entries }
assert_sql(/LIMIT 5|ROWNUM <= 5/) { Topic.last(5).entries }
end
Expand All @@ -218,7 +239,8 @@ def test_last_with_integer_and_reorder_should_not_use_sql_limit
assert_no_match(/LIMIT/, query.first)
end

def test_first_and_last_with_integer_should_return_an_array
def test_take_and_first_and_last_with_integer_should_return_an_array
assert_kind_of Array, Topic.take(5)
assert_kind_of Array, Topic.first(5)
assert_kind_of Array, Topic.last(5)
end
Expand Down

0 comments on commit 1379375

Please sign in to comment.