diff options
author | miloops <miloops@gmail.com> | 2008-09-01 13:36:42 -0300 |
---|---|---|
committer | David Heinemeier Hansson <david@loudthinking.com> | 2008-09-09 23:44:52 -0500 |
commit | 567392bff32acd5cf357565415d33c2662004cf5 (patch) | |
tree | 3b6df7201a8147fd621487721ab5b16bb15c62f1 | |
parent | f3f7d166d8e7a1a2e15371f2870115406e1aaac2 (diff) | |
download | rails-567392bff32acd5cf357565415d33c2662004cf5.tar.gz rails-567392bff32acd5cf357565415d33c2662004cf5.tar.bz2 rails-567392bff32acd5cf357565415d33c2662004cf5.zip |
Added find_last_by dynamic finder [status:committed #762]
Signed-off-by: David Heinemeier Hansson <david@loudthinking.com>
-rw-r--r--[-rwxr-xr-x] | activerecord/lib/active_record/base.rb | 1 | ||||
-rw-r--r-- | activerecord/lib/active_record/dynamic_finder_match.rb | 3 | ||||
-rw-r--r-- | activerecord/test/cases/finder_test.rb | 40 |
3 files changed, 39 insertions, 5 deletions
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 907495a416..0fe9e12549 100755..100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -287,6 +287,7 @@ module ActiveRecord #:nodoc: # It's even possible to use all the additional parameters to find. For example, the full interface for <tt>Payment.find_all_by_amount</tt> # is actually <tt>Payment.find_all_by_amount(amount, options)</tt>. And the full interface to <tt>Person.find_by_user_name</tt> is # actually <tt>Person.find_by_user_name(user_name, options)</tt>. So you could call <tt>Payment.find_all_by_amount(50, :order => "created_on")</tt>. + # Also you may call <tt>Payment.find_last_by_amount(amount, options)</tt> returning the last record matching that amount and options. # # The same dynamic finder style can be used to create the object if it doesn't already exist. This dynamic finder is called with # <tt>find_or_create_by_</tt> and will return the object if it already exists and otherwise creates it, then returns it. Protected attributes won't be set unless they are given in a block. For example: diff --git a/activerecord/lib/active_record/dynamic_finder_match.rb b/activerecord/lib/active_record/dynamic_finder_match.rb index b105b919f5..f4a5712981 100644 --- a/activerecord/lib/active_record/dynamic_finder_match.rb +++ b/activerecord/lib/active_record/dynamic_finder_match.rb @@ -8,7 +8,8 @@ module ActiveRecord def initialize(method) @finder = :find_initial case method.to_s - when /^find_(all_by|by)_([_a-zA-Z]\w*)$/ + when /^find_(all_by|last_by|by)_([_a-zA-Z]\w*)$/ + @finder = :find_last if $1 == 'last_by' @finder = :find_every if $1 == 'all_by' names = $2 when /^find_by_([_a-zA-Z]\w*)\!$/ diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb index 2ce49ed76f..3eee2056dd 100644 --- a/activerecord/test/cases/finder_test.rb +++ b/activerecord/test/cases/finder_test.rb @@ -197,11 +197,11 @@ class FinderTest < ActiveRecord::TestCase first = Topic.find(:first, :conditions => "title = 'The First Topic!'") assert_nil(first) end - + def test_first assert_equal topics(:second).title, Topic.first(:conditions => "title = 'The Second Topic of the day'").title end - + def test_first_failing assert_nil Topic.first(:conditions => "title = 'The Second Topic of the day!'") end @@ -418,7 +418,7 @@ class FinderTest < ActiveRecord::TestCase def test_named_bind_variables assert_equal '1', bind(':a', :a => 1) # ' ruby-mode assert_equal '1 1', bind(':a :a', :a => 1) # ' ruby-mode - + assert_nothing_raised { bind("'+00:00'", :foo => "bar") } assert_kind_of Firm, Company.find(:first, :conditions => ["name = :name", { :name => "37signals" }]) @@ -589,6 +589,38 @@ class FinderTest < ActiveRecord::TestCase assert_nil Topic.find_by_title_and_author_name("The First Topic", "Mary") end + def test_find_last_by_one_attribute + assert_equal Topic.last, Topic.find_last_by_title(Topic.last.title) + assert_nil Topic.find_last_by_title("A title with no matches") + end + + def test_find_last_by_one_attribute_caches_dynamic_finder + # ensure this test can run independently of order + class << Topic; self; end.send(:remove_method, :find_last_by_title) if Topic.public_methods.any? { |m| m.to_s == 'find_last_by_title' } + assert !Topic.public_methods.any? { |m| m.to_s == 'find_last_by_title' } + t = Topic.find_last_by_title(Topic.last) + assert Topic.public_methods.any? { |m| m.to_s == 'find_last_by_title' } + end + + def test_find_last_by_invalid_method_syntax + assert_raises(NoMethodError) { Topic.fail_to_find_last_by_title("The First Topic") } + assert_raises(NoMethodError) { Topic.find_last_by_title?("The First Topic") } + end + + def test_find_last_by_one_attribute_with_several_options + assert_equal accounts(:signals37), Account.find_last_by_credit_limit(50, :order => 'id DESC', :conditions => ['id != ?', 3]) + end + + def test_find_last_by_one_missing_attribute + assert_raises(NoMethodError) { Topic.find_last_by_undertitle("The Last Topic!") } + end + + def test_find_last_by_two_attributes + topic = Topic.last + assert_equal topic, Topic.find_last_by_title_and_author_name(topic.title, topic.author_name) + assert_nil Topic.find_last_by_title_and_author_name(topic.title, "Anonymous") + end + def test_find_all_by_one_attribute topics = Topic.find_all_by_content("Have a nice day") assert_equal 2, topics.size @@ -782,7 +814,7 @@ class FinderTest < ActiveRecord::TestCase assert c.valid? assert !c.new_record? end - + def test_dynamic_find_or_initialize_from_one_attribute_caches_method class << Company; self; end.send(:remove_method, :find_or_initialize_by_name) if Company.public_methods.any? { |m| m.to_s == 'find_or_initialize_by_name' } assert !Company.public_methods.any? { |m| m.to_s == 'find_or_initialize_by_name' } |