shrinerb / shrine

File Attachment toolkit for Ruby applications

Home Page:https://shrinerb.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Exception while trying to marshal ActiveRecord/Sequel model, with attachment & derivatives: no _dump_data is defined for class Thread::Mutex

Morozzzko opened this issue · comments

Brief Description

My app has a case when we need to cache an ActiveRecord object, which has a Shrine attachment.

The attachment's uploader works with two plugins: activerecord and derivatives.

This worked fine under 2.19.4, but broke after our upgrade to 3.3.0

Expected behavior

I expect Rails cache to marshal the provided object and put in the cache. I also expect the object to be functioning properly afterwards

Actual behavior

Whenever I try to marshal a newly-created object with an attachment, I get an exception: no _dump_data is defined for class Thread::Mutex (TypeError)

However, if I try to re-fetch the same object and marshal it, it works fine. #reload doesn't work, though.

Simplest self-contained example code to demonstrate issue

Provide a self-contained example code (see the Sequel/ActiveRecord templates) to show the problem, and the full backtrace of any exception.

ActiveRecord

require 'bundler/inline'

gemfile do
  source 'https://rubygems.org'

  gem 'rails', '5.2.4.4'
  gem 'shrine', '3.3.0'
  gem 'sqlite3'
end

require 'active_record'
require 'shrine'
require 'shrine/storage/memory'
require 'down'

Shrine.storages = {
  cache: Shrine::Storage::Memory.new,
  store: Shrine::Storage::Memory.new
}

Shrine.plugin :activerecord

class MyUploader < Shrine
  plugin :derivatives
end

ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
ActiveRecord::Base.connection.create_table(:posts) { |t| t.text :image_data }

class Post < ActiveRecord::Base
  include MyUploader::Attachment(:image)
end

post = Post.create(image: Down.download('http://theoldreader.com/kittens/600/400/'))

Marshal.dump(post)

# Traceback (most recent call last):
#	1: from reproduce_2.rb:36:in `<main>'
# reproduce.rb:36:in `dump': no _dump_data is defined for class Thread::Mutex (TypeError)


# HOWEVER!

Marshal.dump(post.class.find(post.id)) # works just fine

Marshal.dump(post.reload) # => no _dump_data is defined for class Thread::Mutex (TypeError)

Marshal.dump(post.image) # works just fine

Sequel

require 'bundler/inline'

gemfile do
  source 'https://rubygems.org'

  gem 'sequel'
  gem 'shrine', '3.3.0'
  gem 'sqlite3'
end

require 'sequel'
require 'shrine'
require 'shrine/storage/memory'
require 'down'

Shrine.storages = {
  cache: Shrine::Storage::Memory.new,
  store: Shrine::Storage::Memory.new
}

Shrine.plugin :sequel

class MyUploader < Shrine
  plugin :derivatives
end

DB = Sequel.sqlite # SQLite memory database
DB.create_table :posts do
  primary_key :id
  String :image_data
end

class Post < Sequel::Model
  include MyUploader::Attachment(:image)
end

post = Post.create(image: Down.download('http://theoldreader.com/kittens/600/400/'))

Marshal.dump(post)
# Traceback (most recent call last):
# 	1: from reproduce_sequel.rb:39:in `<main>'
# reproduce_sequel.rb:39:in `dump': no _dump_data is defined for class Thread::Mutex (TypeError)

System configuration

Ruby version: 2.6.5 and 2.7.2

Shrine version: 3.3.0

As it turns out, this problem also exists with Sequel models. Sorry for being so hasty and not considering it before creating the issue

Hey @Morozzzko, thanks for the report 👍

I believe this is happening because the derivatives plugin uses a mutex internally (assigned to an instance variable), which was not the case with the versions plugin. We should probably find a way to exclude it when marshalling.

I'm wondering whether Sequel has some inspiration, as I recall it has some logic for Marshalling, though I suppose it doesn't use mutexes on models directly.

Thanks for the quick reply!

Yes, I've been trying to find the lines which cause the error, and it is indeed the mutex

I'm looking for a solution to exclude it. Thanks for the tip about Sequel! I'll post whatever I find

Sequel hasn't really fixed it, as it turns out. I've managed to marshal ActiveRecord model, but not Sequel model.

However, if I try to marshal _attacher separately, it works now. I think it's good enough for us, since everything works fine on Shrine's side. I'm preparing a PR