This project is archived and is in readonly mode.
caching bugs in ActiveRecord#create and associations
-
nickretallack
- Tag changed from database-caching, find_or_create to create, database-caching, find_or_create
- Title changed from find_or_create causes caching anomalies to caching bugs in ActiveRecord#create and associations
Looks like this isn't just a problem with find_or_create. I can cause a similar problem with regular create. It only takes a little bit of indirection on the very same association to screw things up.
Patch added contains tests that verify the problem
-
RainChen
- Tag changed from create, database-caching, find_or_create to counter_cache, create, database-caching, find_or_create
I still have this issue today (Rails version 2.3.2).
The test code will explain what's wrong.
class Page < ActiveRecord::Base acts_as_tree :counter_cache => :children_count endTest:
require File.dirname(FILE) + '/../test_helper'
class PageTest < ActiveSupport::TestCase context "pages" do
should "have a counter cache" do Page.root.children_count.should == 0 Page.root.children.create(:title => 'about') Page.root.children.count.should == 1 Page.root.children_count.should == 1 Page.root.children.find_or_create_by_title('contact') Page.root.children.count.should == 2 Page.root.children_count.should == 2 # false end
end end
-
nickretallack
This bug still exists. Will it ever be fixed?
-
Neeraj Singh
- Importance changed from to
@nickretallack Do you want to rebase your test against rails3 edge?
-
Neeraj Singh
- State changed from new to open
Just recapping.
class Car has_many :brakes end c = Car.first c.brakes # => 0 . so that all brakes are loaded c.brakes.find_or_create(:name => 'super_brake') # new brake is created c.brakes.length #=> 0 c.brakes.count #=> 1when c.brakes.find_or_create is invoked then method_missing is called and method_missing simply does
@reflection.klass.send(method, *args) { |*block_args| yield(*block_args) }In contrast when car.brakes.create(:name => 'super_brake') is called then add_record_to_target_with_callbacks is called
def add_record_to_target_with_callbacks(record) callback(:before_add, record) yield(record) if block_given? @target ||= [] unless loaded? @target << record unless @reflection.options[:uniq] && @target.include?(record) callback(:after_add, record) set_inverse_instance(record, @owner) record endSo not only cache is not getting refreshed but inverse_instance will also not be set.
-
Aaron Patterson
- Tag changed from counter_cache, create, database-caching, find_or_create to counter_cache, create, database-caching, find_or_create, patch
Added a patch with fixes and tests.
-
Repository
- State changed from open to resolved
(from [fad166c15277c72b370c90e890d509d0f6c9af63]) AssociationCollection#create_by*, find_or_create_by* work properly now. [#1108 caching bugs in ActiveRecord#create and associations state:resolved]
Signed-off-by: Jeremy Kemper jeremy@bitsweat.net
http://github.com/rails/rails/commit/fad166c15277c72b370c90e890d509... -
Repository
(from [3f563f169612ec340816f0a549fe9db7ff95c238]) AssociationCollection#create_by*, find_or_create_by* work properly now. [#1108 caching bugs in ActiveRecord#create and associations state:resolved]
Signed-off-by: Jeremy Kemper jeremy@bitsweat.net
http://github.com/rails/rails/commit/3f563f169612ec340816f0a549fe9d... -
Repository
(from [d5921cdb7a00b393d0ba5f2f795da60a33b11cf1]) Remove unintentional API changes. [#1108 caching bugs in ActiveRecord#create and associations] http://github.com/rails/rails/commit/d5921cdb7a00b393d0ba5f2f795da6...
-
toby cabot
Commit fad166c15277c72b370c90e890d509d0f6c9af63 (i.e. 2.3.9) broke find_or_create_by_x with additional parameters for the create, when called through an association. Since http://dev.rubyonrails.org/ticket/7368 you've been able to pass additional parameters that are ignored by the find but used by the create. fad166c broke that behavior.
I'll attach a test case that demonstrates the problem, but in a nutshell:
# 2.3.8: success # 2.3.9: ArgumentError: Unknown key(s): type, body # ./test/cases/../../../activesupport/lib/active_support/core_ext/hash/keys.rb:47:in `assert_valid_keys' post.comments.find_or_create_by_body(:body => 'other test comment body', :type => 'test') -
toby cabot
fad166c15277c72b370c90e890d509d0f6c9af63 also broke find_or_create_by_x with a block provided. It used to yield to the block but it doesn't anymore. I'll attach another test case that works with 2.3.8 but fails with 2.3.9. For example:
comment = post.comments.find_or_create_by_body('other test comment body') { |comment| comment.type = 'test' } -
toby cabot
Here's a 2-part patch that fixes both problems. The gist of the first part of the patch is to filter parameters provided to a find_or_create_by_x method call so that we only pass the ones to find() that find() cares about. The second part adds code to yield to a provided block.
-
toby cabot
Looks like I can't re-open this bug so I've opened #5737 find_or_create_by_x with create params via association broke in 2.3.9 to track the resolution of these bugs.
-
David Trasbo
- State changed from resolved to open
-
Aaron Patterson
- Assigned user set to Aaron Patterson
-
Ryan Bigg
Automatic cleanup of spam.
-
Aaron Patterson
- State changed from open to resolved
I've applied the patch to the 2-3 branch. Thanks!
-
Ryan Bigg
Automatic cleanup of spam.
-
toby cabot
Thanks Aaron!
