Skip to content

Instantly share code, notes, and snippets.

@AquaGeek
Created May 14, 2011 02:35
Show Gist options
  • Select an option

  • Save AquaGeek/971849 to your computer and use it in GitHub Desktop.

Select an option

Save AquaGeek/971849 to your computer and use it in GitHub Desktop.
Rails Lighthouse ticket #6741
From 86ea94e4d0c228c79b3709f0c667ba90b02e41cd Mon Sep 17 00:00:00 2001
From: Nick Howard <[email protected]>
Date: Sun, 1 May 2011 16:22:46 -0600
Subject: [PATCH] Fix for lighthouse #6741
- adds tests for find_or_create_by and find_or_initialize_by on has_many associations
- changes the behavior of ActiveRecord::Associations::CollectionProxy#method_missing to differ to
ActiveRecord::FinderMethods#find_or_instantiator_by_attributes for arg processing and saving so
find_or_create_by's api on associations will be consistent w/ the api for model classes.
---
.../active_record/associations/collection_proxy.rb | 9 +++++--
.../associations/has_many_associations_test.rb | 24 ++++++++++++++++++++
2 files changed, 30 insertions(+), 3 deletions(-)
diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb
index 388173c..adfc71d 100644
--- a/activerecord/lib/active_record/associations/collection_proxy.rb
+++ b/activerecord/lib/active_record/associations/collection_proxy.rb
@@ -64,9 +64,12 @@ module ActiveRecord
def method_missing(method, *args, &block)
match = DynamicFinderMatch.match(method)
- if match && match.creator?
- attributes = match.attribute_names
- return send(:"find_by_#{attributes.join('_and_')}", *args) || create(Hash[attributes.zip(args)])
+ if match && match.instantiator?
+ record = send(:find_or_instantiator_by_attributes, match, match.attribute_names, *args) do |r|
+ @association.send :set_owner_attributes, r
+ @association.send :add_to_target, r
+ yield(r) if block_given?
+ end
end
if target.respond_to?(method) || ([email protected]_to?(method) && Class.respond_to?(method))
diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb
index 007f11b..247decc 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -605,6 +605,30 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_equal number_of_clients + 1, companies(:first_firm, :reload).clients.size
end
+ def test_find_or_initialize_updates_collection_size
+ number_of_clients = companies(:first_firm).clients_of_firm.size
+ companies(:first_firm).clients_of_firm.find_or_initialize_by_name("name" => "Another Client")
+ assert_equal number_of_clients + 1, companies(:first_firm).clients_of_firm.size
+ end
+
+ def test_find_or_create_with_hash
+ post = authors(:david).posts.find_or_create_by_title(:title => 'Yet another post', :body => 'somebody')
+ assert_equal post, authors(:david).posts.find_or_create_by_title(:title => 'Yet another post', :body => 'somebody')
+ assert post.persisted?
+ end
+
+ def test_find_or_create_with_one_attribute_followed_by_hash
+ post = authors(:david).posts.find_or_create_by_title('Yet another post', :body => 'somebody')
+ assert_equal post, authors(:david).posts.find_or_create_by_title('Yet another post', :body => 'somebody')
+ assert post.persisted?
+ end
+
+ def test_find_or_create_should_work_with_block
+ post = authors(:david).posts.find_or_create_by_title('Yet another post') {|p| p.body = 'somebody'}
+ assert_equal post, authors(:david).posts.find_or_create_by_title('Yet another post') {|p| p.body = 'somebody'}
+ assert post.persisted?
+ end
+
def test_deleting
force_signal37_to_load_all_clients_of_firm
companies(:first_firm).clients_of_firm.delete(companies(:first_firm).clients_of_firm.first)
--
1.7.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment