Shrine: Shrine not promoting to S3 store after upload

Created on 17 May 2017  路  2Comments  路  Source: shrinerb/shrine

Background

Shrine is working flawlessly except for one thing: after the record is created with the data, it is not calling the promote code.

The problem

The upload happens and the image just stays there as cached. I monitor Sidekiq and nothing happens. The Shrine::Attacher.promote block is never called (check below).

require "shrine/storage/s3"

s3_options = {
  access_key_id:     ENV.fetch("S3_ACCESS_KEY_ID"),
  secret_access_key: ENV.fetch("S3_SECRET_ACCESS_KEY"),
  region:            ENV.fetch("S3_REGION"),
  bucket:            ENV.fetch("S3_BUCKET"),
}

Shrine.plugin :activerecord
Shrine.plugin :direct_upload
Shrine.plugin :backgrounding

Shrine::Attacher.promote do |data|
  Rails.logger.info "NEVER CALLED"
  ::Images::PromoteJob.perform_async(data)
end
Shrine::Attacher.delete do |data|
  ::Images::DeleteJob.perform_async(data)
end

Shrine.storages = {
  cache: Shrine::Storage::S3.new(prefix: "cache", **s3_options),
  store: Shrine::Storage::S3.new(prefix: "store", **s3_options),
}

# app/models/media_file.rb
class MediaFile < ActiveRecord::Base
  include FileUploader[:file]

  # ...
end

# app/uploaders/file_uploader.rb
class FileUploader < Shrine
end

# app/controllers/api/files_controller.rb
::MediaFile.create(file_data: metadata.to_json)

Additional details

In the console, calling the following code promotes it. However, it does not do it via Sidekiq, it just processes it for a second without scheduling a job.

#<MediaFile:0x007fdae85e9ed8> {
                 :id => 23,
          :file_data => "{\"id\":\"b9800404be5e39c1c7f79cebc572a93f.jpg\",\"storage\":\"cache\",\"metadata\":{\"size\":\"189404\",\"filename\":\"my-image.jpg\",\"mime_type\":\"image/jpeg\"}}",
         :created_at => Tue, 16 May 2017 23:04:37 -03 -03:00,
         :updated_at => Tue, 16 May 2017 23:04:37 -03 -03:00
}
[2] pry(main)> ::MediaFile.last.file_attacher.promote
  MediaFile Load (0.5ms)  SELECT  "media_files".* FROM "media_files"  ORDER BY "media_files"."id" DESC LIMIT 1
  MediaFile Load (0.4ms)  SELECT  "media_files".* FROM "media_files" WHERE "media_files"."id" = $1  ORDER BY "media_files"."id" ASC LIMIT 1  [["id", 23]]
   (0.2ms)  BEGIN
  SQL (0.4ms)  UPDATE "media_files" SET "file_data" = $1, "updated_at" = $2 WHERE "media_files"."id" = $3  [["file_data", "{\"id\":\"5438a3969e508cd0e81ed09d89df1520.jpg\",\"storage\":\"store\",\"metadata\":{\"size\":\"189404\",\"filename\":\"my-image.jpg\",\"mime_type\":\"image/jpeg\"}}"], ["updated_at", "2017-05-17 02:05:12.853253"], ["id", 23]]
   (1.2ms)  COMMIT
#<FileUploader::UploadedFile:0x007fdae85b9350 @data={"id"=>"5438a3969e508cd0e81ed09d89df1520.jpg", "storage"=>"store", "metadata"=>{"size"=>"189404", "filename"=>"my-image.jpg", "mime_type"=>"image/jpeg"}}>

I don't know where to look at. Do you have any idea what's going on? Where should I start looking to figure out the problem?

Thanks a lot

Most helpful comment

You need to assign the attachment via the Shrine attribute, which is #file in your case.

::MediaFile.create(file: metadata.to_json)

#file_data is just an column attribute generated by your ORM, Shrine doesn't detect any changes to that column. That helps Shrine to be more ORM-agnostic, and it allows users to use the ORM column directly if they wish to bypass Shrine callbacks.

As for the second part of the question, Shrine::Attacher#promote will always be synchronous, regardless of whether you have backgrounding set up or not. This is needed because the Shrine::Attacher.promote method that you call inside the background job calls Shrine::Attacher#promote internally.

To spawn a background job use Shrine::Attacher#_promote. That method will just delegate to Shrine::Attacher#promote if backgrounding plugin is not loaded, but if backgrounding plugin is loaded it will call the registered block.

::MediaFile.last.file_attacher._promote

All 2 comments

You need to assign the attachment via the Shrine attribute, which is #file in your case.

::MediaFile.create(file: metadata.to_json)

#file_data is just an column attribute generated by your ORM, Shrine doesn't detect any changes to that column. That helps Shrine to be more ORM-agnostic, and it allows users to use the ORM column directly if they wish to bypass Shrine callbacks.

As for the second part of the question, Shrine::Attacher#promote will always be synchronous, regardless of whether you have backgrounding set up or not. This is needed because the Shrine::Attacher.promote method that you call inside the background job calls Shrine::Attacher#promote internally.

To spawn a background job use Shrine::Attacher#_promote. That method will just delegate to Shrine::Attacher#promote if backgrounding plugin is not loaded, but if backgrounding plugin is loaded it will call the registered block.

::MediaFile.last.file_attacher._promote

Thanks, good eye. Gonna test tonight.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

brunowego picture brunowego  路  3Comments

janko picture janko  路  8Comments

jakehockey10 picture jakehockey10  路  6Comments

brunowego picture brunowego  路  4Comments

Sohair63 picture Sohair63  路  3Comments