-
Type: Improvement
-
Resolution: Unresolved
-
Priority: Minor - P4
-
None
-
Affects Version/s: 7.0.12, 7.2.2
-
Component/s: Associations, Persistence
-
None
When we have two models and they have both autosave: true in their relations, calling save on a record calls save too many times on other relations. Here is an example :
#!/usr/bin/env ruby require 'bundler/inline' gemfile do source 'https://rubygems.org' gem 'mongoid', '7.0.12' gem 'pry-byebug' end require 'mongoid' Mongoid.configure { |c| c.clients.default = { hosts: ['localhost:27017'], database: 'test' } } puts Mongoid::VERSION puts Mongo::VERSION Mongoid.logger.level = 4 Mongo::Logger.logger.level = 4 class Article include Mongoid::Document has_many :comments, autosave: true before_save :log_save def log_save pp "Article#save" end end class Comment include Mongoid::Document belongs_to :article, autosave: true field :body, type: String before_save :log_save def log_save pp "Comment#save" end end article = Article.new article.comments << Comment.new article.save puts "################################################################################" article.comments << Comment.new article.comments << Comment.new article.save puts "################################################################################" article.comments.last.save
And here is the output :
"Article#save" "Comment#save" "Article#save" ################################################################################ "Comment#save" "Article#save" "Comment#save" "Article#save" "Comment#save" "Comment#save" "Article#save" "Comment#save" "Article#save" "Comment#save" "Article#save" "Comment#save" "Article#save" "Comment#save" "Article#save" "Comment#save" "Article#save" "Comment#save" "Article#save" ################################################################################ "Comment#save" "Article#save" "Comment#save" "Article#save" "Comment#save" "Article#save" "Comment#save"
As you can see, callbacks, validations and saves are trigger a lot too much.
It happens because since this commit records are saved even if there is no change.
In addition, to me, usage of autosave is reasonable here. If we remove autosave we have :
class Article include Mongoid::Document has_many :comments before_save :log_save def log_save pp "Article#save" end end class Comment include Mongoid::Document belongs_to :article field :body, type: String before_save :log_save def log_save pp "Comment#save" end end article = Article.new article.comments << Comment.new article.save pp article.reload.comments # Gives an empty array comment = Comment.create(article: Article.new) pp comment.reload.article # Gives nil
Here we can see the behavior of autosave: true is useful and doesn't seem too crazy.
- depends on
-
MONGOID-4627 Repair incorrect callback behavior during persistence operations
- Development Complete