-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
E11000 duplicate key error collection #5
Comments
Could you provide a self-contained script that reproduces a problem? At the moment I don't quite understand what caused the problem. |
Hey @janko, my old tests for embedded models prove it! :) |
@FunkyloverOne Great, which ones exactly? Could you extract the relevant code into a self-contained script that I can run (on Shrine 3.x and shrine-mongoid 1.x)? |
@janko |
@NikolayMurha Thanks, that helps. It would be ideal if there wasn't any Rails at all, but instead if it was just a script like this one. That would make it the easiest for me to debug and talk about a solution. |
Thank you! 🙏 I'll make sure to look into it later today 👍 |
@NikolayMurha I minimized your script to the following: require "mongoid"
require "shrine"
require "shrine/storage/memory"
Mongoid.configure do |config|
config.clients.default = {
hosts: ["localhost:27017"],
database: "shrine_mongoid_test",
}
end
Shrine.storages = {
cache: Shrine::Storage::Memory.new,
store: Shrine::Storage::Memory.new,
}
Shrine.plugin :mongoid
class Photo
include Mongoid::Document
include Shrine::Attachment[:image]
embedded_in :gallery, polymorphic: true
field :image_data, type: String
end
class Gallery
include Mongoid::Document
embeds_one :photo, class_name: Photo.to_s, autobuild: true, cascade_callbacks: true
accepts_nested_attributes_for :photo, allow_destroy: true
end
Gallery.create(photo_attributes: { image: StringIO.new("image") }) I should be able to look into it tomorrow. If you or @FunkyloverOne have any ideas on what should be done, feel free to let me know 😃 |
It appears that Mongoid calls the What I believe is happening here is the following:
I think that shrine-mongoid would somehow need to know whether the embedded document is being saved standalone, or as part of the parent record save. |
Yes, the order in which Mongoid executes cascading callbacks is definitely very problematic and in my opinion incorrect. If we execute the following script: Scriptrequire "mongoid"
Mongoid.configure do |config|
config.clients.default = {
hosts: ["localhost:27017"],
database: "shrine_mongoid_test",
}
end
class Photo
include Mongoid::Document
before_save { puts "====== before_save Photo" }
after_save { puts "====== after_save Photo" }
embedded_in :gallery, polymorphic: true
field :title, type: String
end
class Gallery
include Mongoid::Document
before_save { puts "====== before_save Gallery" }
after_save { puts "====== after_save Gallery" }
embeds_one :photo, class_name: Photo.to_s, cascade_callbacks: true
accepts_nested_attributes_for :photo, allow_destroy: true
end
Gallery.create(photo_attributes: { title: "Image" }) We can see that Mongoid executes actions in the following order:
So, Perhaps we can add the callback to the top-most parent model, in this case |
I'm not managing to get back to this issue. @FunkyloverOne Would you perhaps be willing to investigate this? You seem to be very knowledgeable in this area, and already had other contributions here 😃 |
Hey @janko, I believe what you said is what we need to do:
And yes, I will actually have time for it soon. 😉 The only thing that bothers me now, is I kinda used to understand how Shrine 2.x worked, but now it's all so different and seems harder. That's gonna be a challenge 😄 |
Yeah, some bigger changes needed to be made, but the core principles largely remained the same, mostly the code got reorganized (e.g. model integration being extracted into plugins). I guess the biggest relevant change was the persistence/backgrounding rewrite. |
@janko how about 2 separate plugins in this gem? |
@FunkyloverOne I'm fine with separating these two things. Could we perhaps make it a plugin option instead? |
Or we could just add # Saves changes to the model instance, raising an exception on validation
# errors. Used by the _persistence plugin.
def mongoid_persist
return if record.embedded?
record.save(validate: false)
end
# Yields the reloaded record. Used by the _persistence plugin.
def mongoid_reload
return yield record if record.embedded?
record_copy = record.dup
record_copy.id = record.id
yield record_copy.reload
end This is misleading though:
Or we could raise an error there because it's more like the user's code shouldn't reach those methods at all. Another solution is to only skip/fail As for Oh, and we should always skip the reload if the root record is not yet persisted! |
Meanwhile, I've figured out that |
And we should only perform that fancy "reload" for an embedded record if it is already persisted within its parent. |
BTW, we might use |
@janko why do we I've just moved the |
Hello.
I have "E11000 duplicate key error collection: project_db.users index: id dup key..."
I investigate this and noticed, that problem in embeded models with cascade_callbacks: true option. This case actual only for new models.
Because this callback called inside insert workflow:
https://github.com/shrinerb/shrine-mongoid/blob/master/lib/shrine/plugins/mongoid.rb#L95
and inserted parent record before main insert executed.
Thanks!
Rails 6.0.1
Mongoid 7.0.5
The text was updated successfully, but these errors were encountered: