aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPratik Naik <pratiknaik@gmail.com>2009-12-27 03:25:29 +0530
committerPratik Naik <pratiknaik@gmail.com>2009-12-27 03:25:29 +0530
commitf6f416c58e805604390314e2e8e5ecf6a0a78b4f (patch)
tree480b570570eb25373c91b9d777806e61e2621b3f
parentcc753eaf589b6dfae92f6fc0031c5710e616a26c (diff)
downloadrails-f6f416c58e805604390314e2e8e5ecf6a0a78b4f.tar.gz
rails-f6f416c58e805604390314e2e8e5ecf6a0a78b4f.tar.bz2
rails-f6f416c58e805604390314e2e8e5ecf6a0a78b4f.zip
Add find_by_* and find_all_by_* finders to ActiveRecord::Relation
-rw-r--r--activerecord/lib/active_record/relation.rb14
-rw-r--r--activerecord/test/cases/relations_test.rb34
2 files changed, 47 insertions, 1 deletions
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index b6800b07b7..f9ca6cbbd2 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -136,6 +136,20 @@ module ActiveRecord
@relation.send(method, *args, &block)
elsif Array.method_defined?(method)
to_a.send(method, *args, &block)
+ elsif match = DynamicFinderMatch.match(method)
+ attributes = match.attribute_names
+ super unless @klass.send(:all_attributes_exists?, attributes)
+
+ if match.finder?
+ conditions = attributes.inject({}) {|h, a| h[a] = args[attributes.index(a)]; h}
+ result = where(conditions).send(match.finder)
+
+ if match.bang? && result.blank?
+ raise RecordNotFound, "Couldn't find #{@klass.name} with #{conditions.to_a.collect {|p| p.join(' = ')}.join(', ')}"
+ else
+ result
+ end
+ end
else
super
end
diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb
index e05da58ae6..f94402f57e 100644
--- a/activerecord/test/cases/relations_test.rb
+++ b/activerecord/test/cases/relations_test.rb
@@ -1,4 +1,6 @@
require "cases/helper"
+require 'models/tag'
+require 'models/tagging'
require 'models/post'
require 'models/topic'
require 'models/comment'
@@ -10,7 +12,8 @@ require 'models/developer'
require 'models/company'
class RelationTest < ActiveRecord::TestCase
- fixtures :authors, :topics, :entrants, :developers, :companies, :developers_projects, :accounts, :categories, :categorizations, :posts, :comments
+ fixtures :authors, :topics, :entrants, :developers, :companies, :developers_projects, :accounts, :categories, :categorizations, :posts, :comments,
+ :taggings
def test_scoped
topics = Topic.scoped
@@ -222,5 +225,34 @@ class RelationTest < ActiveRecord::TestCase
post = posts.find { |p| p.id == 1 }
assert_equal Post.find(1).last_comment, post.last_comment
end
+
+ def test_dynamic_find_by_attributes
+ david = authors(:david)
+ author = Author.preload(:taggings).find_by_id(david.id)
+ expected_taggings = taggings(:welcome_general, :thinking_general)
+
+ assert_no_queries do
+ assert_equal expected_taggings, author.taggings.uniq.sort_by { |t| t.id }
+ end
+
+ authors = Author.scoped
+ assert_equal david, authors.find_by_id_and_name(david.id, david.name)
+ assert_equal david, authors.find_by_id_and_name!(david.id, david.name)
+ end
+
+ def test_dynamic_find_by_attributes_bang
+ author = Author.scoped.find_by_id!(authors(:david).id)
+ assert_equal "David", author.name
+
+ assert_raises(ActiveRecord::RecordNotFound) { Author.scoped.find_by_id_and_name!('invalid', 'wt') }
+ end
+
+ def test_dynamic_find_all_by_attributes
+ authors = Author.scoped
+
+ davids = authors.find_all_by_name('David')
+ assert_kind_of Array, davids
+ assert_equal [authors(:david)], davids
+ end
end