From 1092c181b5568d06e84f6a3253aaca81c02a2b2c Mon Sep 17 00:00:00 2001 From: Josh Susser Date: Mon, 25 Aug 2008 21:28:53 -0700 Subject: [PATCH] add dynamic finder bang version to raise RecordNotFound [#905 state:resolved] Signed-off-by: Jeremy Kemper --- activerecord/lib/active_record/base.rb | 4 +++- .../lib/active_record/dynamic_finder_match.rb | 7 +++++++ activerecord/test/cases/finder_test.rb | 14 ++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 523b619e62..5c30f80555 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1679,6 +1679,7 @@ module ActiveRecord #:nodoc: super unless all_attributes_exists?(attribute_names) if match.finder? finder = match.finder + bang = match.bang? self.class_eval %{ def self.#{method_id}(*args) options = args.extract_options! @@ -1687,13 +1688,14 @@ module ActiveRecord #:nodoc: validate_find_options(options) set_readonly_option!(options) - if options[:conditions] + #{'result = ' if bang}if options[:conditions] with_scope(:find => finder_options) do ActiveSupport::Deprecation.silence { send(:#{finder}, options) } end else ActiveSupport::Deprecation.silence { send(:#{finder}, options.merge(finder_options)) } end + #{'result || raise(RecordNotFound)' if bang} end }, __FILE__, __LINE__ send(method_id, *arguments) diff --git a/activerecord/lib/active_record/dynamic_finder_match.rb b/activerecord/lib/active_record/dynamic_finder_match.rb index 4618e777a4..b105b919f5 100644 --- a/activerecord/lib/active_record/dynamic_finder_match.rb +++ b/activerecord/lib/active_record/dynamic_finder_match.rb @@ -11,6 +11,9 @@ module ActiveRecord when /^find_(all_by|by)_([_a-zA-Z]\w*)$/ @finder = :find_every if $1 == 'all_by' names = $2 + when /^find_by_([_a-zA-Z]\w*)\!$/ + @bang = true + names = $1 when /^find_or_(initialize|create)_by_([_a-zA-Z]\w*)$/ @instantiator = $1 == 'initialize' ? :new : :create names = $2 @@ -29,5 +32,9 @@ module ActiveRecord def instantiator? @finder == :find_initial && !@instantiator.nil? end + + def bang? + @bang + end end end diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb index 875d56f6c1..2ce49ed76f 100644 --- a/activerecord/test/cases/finder_test.rb +++ b/activerecord/test/cases/finder_test.rb @@ -25,6 +25,15 @@ class DynamicFinderMatchTest < ActiveRecord::TestCase assert_equal %w(age sex location), match.attribute_names end + def find_by_bang + match = ActiveRecord::DynamicFinderMatch.match("find_by_age_and_sex_and_location!") + assert_not_nil match + assert match.finder? + assert match.bang? + assert_equal :find_initial, match.finder + assert_equal %w(age sex location), match.attribute_names + end + def test_find_all_by match = ActiveRecord::DynamicFinderMatch.match("find_all_by_age_and_sex_and_location") assert_not_nil match @@ -482,6 +491,11 @@ class FinderTest < ActiveRecord::TestCase assert_nil Topic.find_by_title("The First Topic!") end + def test_find_by_one_attribute_bang + assert_equal topics(:first), Topic.find_by_title!("The First Topic") + assert_raises(ActiveRecord::RecordNotFound) { Topic.find_by_title!("The First Topic!") } + end + def test_find_by_one_attribute_caches_dynamic_finder # ensure this test can run independently of order class << Topic; self; end.send(:remove_method, :find_by_title) if Topic.public_methods.any? { |m| m.to_s == 'find_by_title' }