[1] pry(main)> Node.last.posts
Node Load (0.2ms) SELECT `nodes`.* FROM `nodes` ORDER BY `nodes`.`id` DESC LIMIT 1
Post Load (0.4ms) SELECT `posts`.* FROM `posts` WHERE `posts`.`node_id` = 5
=> []
[2] pry(main)> Post.first.node = Node.last
Node Load (0.1ms) SELECT `nodes`.* FROM `nodes` ORDER BY `nodes`.`id` DESC LIMIT 1
SQL (0.3ms) UPDATE `nodes` SET `posts_count` = COALESCE(`posts_count`, 0) + 1 WHERE `nodes`.`id` = 5
SQL (0.3ms) UPDATE `nodes` SET `posts_count` = COALESCE(`posts_count`, 0) - 1 WHERE `nodes`.`id` = 1
=> #<Node id: 5, name: "ttt", cover: nil, description: nil, created_at: "2013-01-18 21:34:14", updated_at: "2013-01-18 22:15:41", posts_count: 0, state: "publish">
[3] pry(main)> Post.first.node
=> #<Node id: 1, name: "System", cover: nil, description: "", created_at: "2012-12-07 18:29:00", updated_at: "2012-12-07 18:40:03", posts_count: 4, state: "system">
[4] pry(main)> Node.last.posts_count
Node Load (0.4ms) SELECT `nodes`.* FROM `nodes` ORDER BY `nodes`.`id` DESC LIMIT 1
=> 1
[5] pry(main)> Node.last.posts
Node Load (0.4ms) SELECT `nodes`.* FROM `nodes` ORDER BY `nodes`.`id` DESC LIMIT 1
Post Load (0.3ms) SELECT `posts`.* FROM `posts` WHERE `posts`.`node_id` = 5
=> []
[6] pry(main)> Node.last.posts_count
Node Load (0.4ms) SELECT `nodes`.* FROM `nodes` ORDER BY `nodes`.`id` DESC LIMIT 1
=> 1
updating counter occur in assigning, but the resource maybe not save, that will made counter incorrectly, why don't update counter after resource update?
update
lib/active_record/associations/builder/belongs_to.rb
method_name = "belongs_to_counter_cache_after_create_for_#{name}"
mixin.redefine_method(method_name) do
record = send(name)
record.class.increment_counter(cache_column, record.id) unless record.nil?
end
model.after_create(method_name)
method_name = "belongs_to_counter_cache_before_destroy_for_#{name}"
mixin.redefine_method(method_name) do
record = send(name)
record.class.decrement_counter(cache_column, record.id) unless record.nil?
end
model.before_destroy(method_name)
we can learn that AR will update counter at resource create and destroy, there is a question: why before destroy not after destroy? although there has transaction to ensure consistency but 'after' is more reasonable.
def replace(record)
raise_on_type_mismatch(record) if record
update_counters(record)
replace_keys(record)
set_inverse_instance(record)
@updated = true if record
self.target = record
end
this will affect on assigning, it will update counter immediately, but has potential problem as I said above.
I think AR should ensure final consistency, so update counter after persistence.
updating counter occur in assigning, but the resource maybe not save, that will made counter incorrectly, why don't update counter after resource update?
update
lib/active_record/associations/builder/belongs_to.rb
we can learn that AR will update counter at resource create and destroy, there is a question: why before destroy not after destroy? although there has transaction to ensure consistency but 'after' is more reasonable.
this will affect on assigning, it will update counter immediately, but has potential problem as I said above.
I think AR should ensure final consistency, so update counter after persistence.