From f6f416c58e805604390314e2e8e5ecf6a0a78b4f Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sun, 27 Dec 2009 03:25:29 +0530 Subject: Add find_by_* and find_all_by_* finders to ActiveRecord::Relation --- activerecord/lib/active_record/relation.rb | 14 ++++++++++++ activerecord/test/cases/relations_test.rb | 34 +++++++++++++++++++++++++++++- 2 files changed, 47 insertions(+), 1 deletion(-) 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 -- cgit v1.2.3