Environment:
MacOSX 10.6.8 Ruby 1.9.3-p125 MongoDB
db version v2.0.3, pdfile version 4.5
Tue Apr 3 14:47:32 git version: 05bb8aa793660af8fce7e36b510ad48c27439697
Rails 3.2.1 Mongoid 2.4.5 carrierwave-mongoid 0.1.3
Have run into this problem when the Mongoid::IdentityMap is on and I upload a file with a different name. We are storing zip files in GridFS.
What we are seeing is that this is not a bug per se in carrierwave but rather, when the IdenitityMap is on the work that carrierwave does to determine if the old file should be removed is farked up by the map. Long boring details of what I observed are at the end of this submission.
Looking at carrierwave code (and the carrierwave-mongoid code) we think that the
before_filter :store_previous_model_for<column>
fetches a pristine copy of the record by calling the carrierwave-mongoid version of
find_previous_model_for<column>
so the after_save filter can compare the two and remove the old file if need be.
But with the IdentityMap on find_previous(...) will pull the record from the IdentityMap and will not fetch a pristine copy of the record from the database. Thus carrierwave's checks fail and the old file is not remove from the store.
Alas, I see no facility in Mongoid to bypass the IdentityMap in this case. Perhaps I will bug the Mongoid folks or make a patch for them myself. Something like this could be used by carrierwave-mongoid to fix this issue:
(carrierwave-mongoid) /lib/carrierwave/mongoid.rb
def find_previous_model_for_#{column}
self.ignore_identity_map do # this does not exist in Mongoid today
if self.embedded?
ancestors = [[ self.metadata.key, self._parent ]].tap { |x| x.unshift([ x.first.last.metadata.key, x.first.last._parent ]) while x.first.last.embedded? }
first_parent = ancestors.first.last
reloaded_parent = first_parent.class.find(first_parent.to_key.first)
association = ancestors.inject(reloaded_parent) { |parent,(key,ancestor)| (parent.is_a?(Array) ? parent.find(ancestor.to_key.first) : parent).send(key) }
association.is_a?(Array) ? association.find(to_key.first) : association
else
self.class.find(to_key.first)
end
end
end
So that's my issue. Right now I think it's not fixable without a change in Mongoid itself.
rails console
>> s = Site.first
=> #<Site _id: 4f7b3c189cf77ec43f000002, _type: nil, created_at: 2012-04-03 18:06:16 UTC, name: "NOSM", file_map: {}, site_zip: nil>
>> s.site_zip = File.open('/Users/glongman/Downloads/smacss.zip')
=> #<File:/Users/glongman/Downloads/smacss.zip>
>> s.save
=> true
mongo query showing the first zip in the db:
> db.fs.files.find({filename: /.*.zip/})
{ "_id" : ObjectId("4f7b3b829cf77ec305000001"),
"filename" : "/sites/4f79b80e9cf77e1b86000002/smacss.zip", "contentType" : "binary/octet-stream", "length" : 1278914, "chunkSize" : 262144, "uploadDate" : ISODate("2012-04-03T18:03:46.470Z"), "md5" : "e95487ea11a61b6e504018975aaaf4cd" }
Now we return to the console and replace the attached zip with another one
>> s.site_zip = File.open('/Users/glongman/Downloads/nosm.zip')
=> #<File:/Users/glongman/Downloads/nosm.zip>
>> s.save
=> true
And the db shows that carrierwave replaced smacss.zip with nosm.zip
> db.fs.files.find({filename: /.*.zip/})
{ "_id" : ObjectId("4f7b3bf29cf77ec436000007"),
"filename" : "/sites/4f7b3bb89cf77ec431000002/nosm.zip", "contentType" : "binary/octet-stream", "length" : 336729, "chunkSize" : 262144, "uploadDate" : ISODate("2012-04-03T18:05:38.664Z"), "md5" : "54aacc97b24fa23d5fd322b21c3b0d38" }
Attachments from previous were removed before starting
>> s = Site.first
=> #<Site _id: 4f7b3c189cf77ec43f000002, _type: nil, created_at: 2012-04-03 18:06:16 UTC, name: "NOSM", file_map: {}, site_zip: nil>
>> s.site_zip = File.open('/Users/glongman/Downloads/smacss.zip')
=> #<File:/Users/glongman/Downloads/smacss.zip>
>> s.save
=> true
> db.fs.files.find({filename: /.*.zip/})
{ "_id" : ObjectId("4f7b3c2f9cf77ec444000001"),
"filename" : "/sites/4f7b3c189cf77ec43f000002/smacss.zip", "contentType" : "binary/octet-stream", "length" : 1278914, "chunkSize" : 262144, "uploadDate" : ISODate("2012-04-03T18:06:39.440Z"), "md5" : "e95487ea11a61b6e504018975aaaf4cd" }
>> s.site_zip = File.open('/Users/glongman/Downloads/nosm.zip')
=> #<File:/Users/glongman/Downloads/nosm.zip>
>> s.save
=> true
> db.fs.files.find({filename: /.*.zip/})
{ "_id" : ObjectId("4f7b3c499cf77ec444000007"),
"filename" : "/sites/4f7b3c189cf77ec43f000002/nosm.zip", "contentType" : "binary/octet-stream", "length" : 336729, "chunkSize" : 262144, "uploadDate" : ISODate("2012-04-03T18:07:05.288Z"), "md5" : "54aacc97b24fa23d5fd322b21c3b0d38" }
{ "_id" : ObjectId("4f7b3c2f9cf77ec444000001"),
"filename" : "/sites/4f7b3c189cf77ec43f000002/smacss.zip", "contentType" : "binary/octet-stream", "length" : 1278914, "chunkSize" : 262144, "uploadDate" : ISODate("2012-04-03T18:06:39.440Z"), "md5" : "e95487ea11a61b6e504018975aaaf4cd" }
:(