Skip to content

Instantly share code, notes, and snippets.

@openfirmware
Created December 16, 2010 02:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save openfirmware/742909 to your computer and use it in GitHub Desktop.
Save openfirmware/742909 to your computer and use it in GitHub Desktop.
[PATCH] Fix find_or_create_by_x on association bug [#6147 state:resolved]
From 12c8326e8c6c1f21a6b56f4d0a5fcdb932d0fa56 Mon Sep 17 00:00:00 2001
From: James Badger <Jamesbadger@gmail.com>
Date: Wed, 15 Dec 2010 15:55:51 -0700
Subject: [PATCH] Fix find_or_create_by_x on association bug [#6147 state:resolved]
Commit fdfc8e3b9c4905057677fd009f463a377be60b93 fixed the
find_or_create_by_x find() being confused by the extra parameters,
but the create_by_x code from b64d1fe637d16916c59e2ddec403d9c7cd54b0f8
does not convert the array properly for create(). This patch allows
sending of params with additional hash attributes by changing the
array conversion method.
---
.../associations/association_collection.rb | 4 ++-
.../associations/has_many_associations_test.rb | 32 ++++++++++++++++++++
2 files changed, 35 insertions(+), 1 deletions(-)
diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb
index 3a602e4..3490980 100644
--- a/activerecord/lib/active_record/associations/association_collection.rb
+++ b/activerecord/lib/active_record/associations/association_collection.rb
@@ -384,7 +384,9 @@ module ActiveRecord
return send("find_by_#{rest}", find_args) ||
method_missing("create_by_#{rest}", *args, &block)
when /^create_by_(.*)$/
- return create($1.split('_and_').zip(args).inject({}) { |h,kv| k,v=kv ; h[k] = v ; h }, &block)
+ hash = $1.split('_and_').zip(args).inject({}) { |h,kv| k,v=kv ; h[k.to_sym] = v ; h }
+ hash.merge!(args.inject({}) { |h,v| v.is_a?(Hash) ? h.merge(v) : h })
+ return create(hash, &block)
end
if @target.respond_to?(method) || (!@reflection.klass.respond_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 3996b84..062929f 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -82,6 +82,38 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_equal 4, post.comments.length
end
+ def test_find_or_create_by_with_hash_sets_proper_attributes
+ author = Author.create!(:name => "Sir Vayor")
+ post = author.posts.create!(:title => "A fine post", :body => "It is fine, is it not?")
+ assert_equal 1, author.posts.count
+ assert_equal 1, author.posts.length
+ assert_equal post, author.posts.find_or_create_by_title("A fine post")
+
+ post = author.posts.find_or_create_by_title(:title => "A wood post", :body => "It is made of wood.")
+ assert_equal 2, author.posts.count
+ assert_equal 2, author.posts.length
+ assert_equal "A wood post", post.title
+ assert_equal "It is made of wood.", post.body
+
+ post = author.posts.find_or_create_by_title("An iron post", :body => "A heavy post made of iron.")
+ assert_equal 3, author.posts.count
+ assert_equal 3, author.posts.length
+ assert_equal "An iron post", post.title
+ assert_equal "A heavy post made of iron.", post.body
+
+ post = author.posts.find_or_create_by_title_and_body("A witness post", "The other post was near here.")
+ assert_equal 4, author.posts.count
+ assert_equal 4, author.posts.length
+ assert_equal "A witness post", post.title
+ assert_equal "The other post was near here.", post.body
+
+ post = author.posts.find_or_create_by_title_and_body("The last post", "If only they were this easy to find.", {:title => "Maybe not the last post", :body => "Another post."})
+ assert_equal 5, author.posts.count
+ assert_equal 5, author.posts.length
+ assert_equal "Maybe not the last post", post.title
+ assert_equal "Another post.", post.body
+ end
+
def test_find_or_create_by_with_block
post = Post.create! :title => 'test_find_or_create_by_with_additional_parameters', :body => 'this is the body'
comment = post.comments.find_or_create_by_body('other test comment body') { |comment| comment.type = 'test' }
--
1.7.0.4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment