-
Notifications
You must be signed in to change notification settings - Fork 276
Open
Description
When using backgrounding, creating a new record in the DB with a file attached does not have the ID yet when storing in the cache/ directory. Is this expected behavior? Does it make any meaningful difference? The permanent storage does end up getting the model ID in the stored directory.
Using Rails 8, Ruby 3.4:
rails new shrine_tester -T
bundle add shrine rspec-rails factory_bot_rails
rails g rspec:install
rails g model post image_data:text
# config/initializers/shrine.rb
require "shrine"
require "shrine/storage/file_system"
Shrine.storages = {
cache: Shrine::Storage::FileSystem.new("public", prefix: "uploads/cache"), # temporary
store: Shrine::Storage::FileSystem.new("public", prefix: "uploads"), # permanent
}
Shrine.plugin :activerecord
Shrine.plugin :backgrounding
Shrine.plugin :pretty_location
Shrine::Attacher.promote_block do
PromoteFileJob.perform_later(self.class.name, record.class.name, record.id, name, file_data)
end
# app/jobs/promote_file_job.rb
class PromoteFileJob < ApplicationJob
def perform(attacher_klass_name, record_klass, record_id, name, file)
attacher_klass = Object.const_get(attacher_klass_name)
model = Object.const_get(record_klass).find(record_id)
attacher = attacher_klass.retrieve(model:, name:, file:)
attacher.atomic_promote
rescue Shrine::AttachmentChanged, ActiveRecord::RecordNotFound
# attachment has changed or record has been deleted, nothing to do
end
end
# app/uploaders/uploader.rb
class Uploader < Shrine
end
# db/migrate/20250204162317_create_posts.rb
class CreatePosts < ActiveRecord::Migration[8.0]
def change
create_table :posts do |t|
t.text :image_data
t.timestamps
end
end
end
# app/models/post.rb
class Post < ApplicationRecord
include Uploader[:image]
end
# spec/factories/posts.rb
FactoryBot.define do
factory :post do
image { File.open("spec/fixtures/test.png") }
end
end
# spec/models/post_spec.rb
require 'rails_helper'
RSpec.describe Post, type: :model do
specify do
post = FactoryBot.create(:post)
expect(post.image.url).to include("post/#{post.id}/image")
end
end
> rake
/home/joemsak/.asdf/installs/ruby/3.4.1/bin/ruby -I/home/joemsak/.asdf/installs/ruby/3.4.1/lib/ruby/gems/3.4.0/gems/rspec-core-3.13.2/lib:/home/joemsak/.asdf/installs/ruby/3.4.1/lib/ruby/gems/3.4.0/gems/rspec-support-3.13.2/lib /home/joemsak/.asdf/installs/ruby/3.4.1/lib/ruby/gems/3.4.0/gems/rspec-core-3.13.2/exe/rspec --pattern spec/\*\*\{,/\*/\*\*\}/\*_spec.rb
F
Failures:
1) Post is expected to include "post/1/image"
Failure/Error: expect(post.image.url).to include("post/#{post.id}/image")
expected "/uploads/cache/post/image/9296ceac0a51c88ec1dce2c1789d87dc.png" to include "post/1/image"
# ./spec/models/post_spec.rb:6:in 'block (2 levels) in <top (required)>'
Finished in 0.01495 seconds (files took 0.55001 seconds to load)
1 example, 1 failure
Failed examples:
rspec ./spec/models/post_spec.rb:4 # Post is expected to include "post/1/image"
/home/joemsak/.asdf/installs/ruby/3.4.1/bin/ruby -I/home/joemsak/.asdf/installs/ruby/3.4.1/lib/ruby/gems/3.4.0/gems/rspec-core-3.13.2/lib:/home/joemsak/.asdf/installs/ruby/3.4.1/lib/ruby/gems/3.4.0/gems/rspec-support-3.13.2/lib /home/joemsak/.asdf/installs/ruby/3.4.1/lib/ruby/gems/3.4.0/gems/rspec-core-3.13.2/exe/rspec --pattern spec/\*\*\{,/\*/\*\*\}/\*_spec.rb failed
➜ shrine_tester git:(main) ✗
Metadata
Metadata
Assignees
Labels
No labels