I have a rails 7 app with shrinerb and filepond. I am
having issues with the filename sticking in metadata. I have tried a lot
of workarounds with nothing working. It seems no matter what the value
is null EXCEPT when I first upload initially its there. It seems its
lost in space at some point between initial upload and cache storage
where it doesn't stay in image_data.
uploads_controller.rb create action:
def create
begin
uploaded_file = ImageUploader.upload(params[:file], :cache)
Rails.logger.debug "Metadata: #{uploaded_file.metadata.inspect}"
if uploaded_file
render json: { id: uploaded_file.id, storage: 'cache', metadata: uploaded_file.metadata }
Rails.logger.debug "UPLOADED_FILE_Metadata: #{uploaded_file.metadata.inspect}"
else
render json: { error: "File upload failed" }, status: :unprocessable_entity
end
rescue => e
Rails.logger.error "Upload failed: #{e.message}"
render json: { error: e.message }, status: :unprocessable_entity
end
end
OUTPUT from uploads create with debug logging:
Started POST "/uploads" for 127.0.0.1 at 2024-04-05 16:38:13 -0400
Processing by UploadsController#create as */*
Parameters: {"file"=>#<ActionDispatch::Http::UploadedFile:0x00000218f792cfe0 @tempfile=#<Tempfile:C:/Users/keith/AppData/Local/Temp/RackMultipart20240405-118100-uq8i0z.jpg>, @content_type="image/jpeg", @original_filename="3S0A3507.jpg", @headers="Content-Disposition: form-data; name=\"file\"; filename=\"3S0A3507.jpg\"\r\nContent-Type: image/jpeg\r\n">, "fileData"=>"{\"filename\":\"3S0A3507.jpg\"}"}
Metadata: {"filename"=>"3S0A3507.jpg", "size"=>31576058, "mime_type"=>"image/jpeg", "width"=>8192, "height"=>5464}
UPLOADED_FILE_Metadata: {"filename"=>"3S0A3507.jpg", "size"=>31576058, "mime_type"=>"image/jpeg", "width"=>8192, "height"=>5464}
Completed 200 OK in 50ms (Views: 0.2ms | ActiveRecord: 0.0ms | Allocations: 1897)
From here it goes to my locations_controller where I have a
create action which will call an attach method to attach the images to
the location.
my locations controller create action:
def create
@location = current_user.locations.build(location_params.except(:uploaded_photos))
puts params.inspect
# This is for debugging; consider removing it in production
if params[:location][:uploaded_photos].present?
attach_uploaded_photos(@location, params[:location][:uploaded_photos])
end
if @location.save
respond_to do |format|
format.html { redirect_to locations_path }
format.turbo_stream do
render turbo_stream: turbo_stream.append("locationsUl", partial: "location", locals: { location: @location })
end
# Handle JSON response for AJAX requests
format.json { render json: @location, status: :created }
end
else
respond_to do |format|
format.html { render :new, status: :unprocessable_entity }
format.turbo_stream { render turbo_stream: turbo_stream.replace(@location, partial: "locations/form", locals: { location: @location }) }
# Handle JSON response for errors during AJAX requests
format.json { render json: @location.errors.full_messages, status: :unprocessable_entity }
end
end
end
locations controller attach:
def attach_uploaded_photos(location, uploaded_photo_ids)
uploaded_photo_ids.each do |photo_id|
uploaded_file = ImageUploader.uploaded_file(storage: 'cache', id: photo_id)
uploaded_file.refresh_metadata!
if uploaded_file.exists?
Rails.logger.debug "Cached file: #{uploaded_file.inspect}"
# No need for file_data parsing, directly use image_data
photo = location.photos.build(image: uploaded_file, image_data: uploaded_file.metadata)
if photo.save
Rails.logger.debug "Photo attached successfully with metadata: #{photo.image.metadata.inspect}"
else
Rails.logger.error "Failed to attach photo: #{photo.errors.full_messages.join(", ")}"
end
else
Rails.logger.error "Uploaded file with ID #{photo_id} not found or does not exist."
end
end
end
From start to end logging:
Started POST "/uploads" for 127.0.0.1 at 2024-04-05 16:44:26 -0400
Processing by UploadsController#create as */*
Parameters: {"file"=>#<ActionDispatch::Http::UploadedFile:0x0000020cba6ce7d8 @tempfile=#<Tempfile:C:/Users/keith/AppData/Local/Temp/RackMultipart20240405-116412-dnmgv8.jpg>, @content_type="image/jpeg", @original_filename="3S0A3507.jpg", @headers="Content-Disposition: form-data; name=\"file\"; filename=\"3S0A3507.jpg\"\r\nContent-Type: image/jpeg\r\n">, "fileData"=>"{\"filename\":\"3S0A3507.jpg\"}"}
Metadata: {"filename"=>"3S0A3507.jpg", "size"=>31576058, "mime_type"=>"image/jpeg", "width"=>8192, "height"=>5464}
UPLOADED_FILE_Metadata: {"filename"=>"3S0A3507.jpg", "size"=>31576058, "mime_type"=>"image/jpeg", "width"=>8192, "height"=>5464}
Completed 200 OK in 50ms (Views: 0.2ms | ActiveRecord: 0.0ms | Allocations: 2350)
Started POST "/locations" for 127.0.0.1 at 2024-04-05 16:44:28 -0400
Processing by LocationsController#create as TURBO_STREAM
Parameters: {"authenticity_token"=>"[FILTERED]", "location"=>{"name"=>"", "details"=>"", "street_address"=>"", "location_type"=>"Indoor", "uploaded_photos"=>["eda3b15fc85d884cd7280d8ffc1bf6fc.jpg"]}, "file"=>"{\"id\":\"eda3b15fc85d884cd7280d8ffc1bf6fc.jpg\",\"storage\":\"cache\",\"metadata\":{\"filename\":\"3S0A3507.jpg\",\"size\":31576058,\"mime_type\":\"image/jpeg\",\"width\":8192,\"height\":5464}}", "commit"=>"Add Location"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ? [["id", 4], ["LIMIT", 1]]
#<ActionController::Parameters {"authenticity_token"=>"WqHPOPhdNuni0N5C2BW2IUiLCdra5mpwnH7xNd_PTaVd7_bWJqBBESwNdsyR1vKoAk5Z1OBw7SRcFDNtsBHUkA", "location"=>#<ActionController::Parameters {"name"=>"", "details"=>"", "street_address"=>"", "location_type"=>"Indoor", "uploaded_photos"=>["eda3b15fc85d884cd7280d8ffc1bf6fc.jpg"]} permitted: false>, "file"=>"{\"id\":\"eda3b15fc85d884cd7280d8ffc1bf6fc.jpg\",\"storage\":\"cache\",\"metadata\":{\"filename\":\"3S0A3507.jpg\",\"size\":31576058,\"mime_type\":\"image/jpeg\",\"width\":8192,\"height\":5464}}", "commit"=>"Add Location", "controller"=>"locations", "action"=>"create"} permitted: false>
Cached file: #<ImageUploader::UploadedFile storage=:cache id="eda3b15fc85d884cd7280d8ffc1bf6fc.jpg" metadata={"filename"=>nil, "size"=>31576058, "mime_type"=>"image/jpeg", "width"=>8192, "height"=>5464}>
TRANSACTION (0.1ms) begin transaction
↳ app/controllers/locations_controller.rb:131:in `block in attach_uploaded_photos'
Location Create (15.1ms) INSERT INTO "locations" ("name", "details", "street_address", "city", "state", "zip_code", "created_at", "updated_at", "user_id", "location_type") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) [["name", ""], ["details", ""], ["street_address", ""], ["city", nil], ["state", nil], ["zip_code", nil], ["created_at", "2024-04-05 20:44:28.256691"], ["updated_at", "2024-04-05 20:44:28.256691"], ["user_id", 4], ["location_type", "Indoor"]]
↳ app/controllers/locations_controller.rb:131:in `block in attach_uploaded_photos'
Photo Create (0.2ms) INSERT INTO "photos" ("location_id", "image_data", "created_at", "updated_at", "file_id") VALUES (?, ?, ?, ?, ?) [["location_id", 6], ["image_data", "{\"filename\"=>nil, \"size\"=>31576058, \"mime_type\"=>\"image/jpeg\", \"width\"=>8192, \"height\"=>5464}"], ["created_at", "2024-04-05 20:44:28.276100"], ["updated_at", "2024-04-05 20:44:28.276100"], ["file_id", nil]]
↳ app/controllers/locations_controller.rb:131:in `block in attach_uploaded_photos'
TRANSACTION (4.8ms) commit transaction
↳ app/controllers/locations_controller.rb:131:in `block in attach_uploaded_photos'
TRANSACTION (0.0ms) begin transaction
↳ app/controllers/locations_controller.rb:131:in `block in attach_uploaded_photos'
Photo Update (0.9ms) UPDATE "photos" SET "image_data" = ?, "updated_at" = ? WHERE "photos"."id" = ? [["image_data", "{\"id\":\"05131c3fafcdda37691051426f99187f.jpg\",\"storage\":\"store\",\"metadata\":{\"filename\":null,\"size\":31576058,\"mime_type\":\"image/jpeg\",\"width\":8192,\"height\":5464}}"], ["updated_at", "2024-04-05 20:44:28.344441"], ["id", 20]]
↳ app/controllers/locations_controller.rb:131:in `block in attach_uploaded_photos'
TRANSACTION (4.3ms) commit transaction
↳ app/controllers/locations_controller.rb:131:in `block in attach_uploaded_photos'
Photo attached successfully with metadata: {"filename"=>nil, "size"=>31576058, "mime_type"=>"image/jpeg", "width"=>8192, "height"=>5464}
Rendered locations/_location.html.erb (Duration: 0.9ms | Allocations: 537)
Completed 200 OK in 191ms (Views: 0.1ms | ActiveRecord: 25.6ms | Allocations: 25633)
photo model:
class Photo < ApplicationRecord
include ImageUploader::Attachment(:image) # Assumes you have an ImageUploader for Shrine
belongs_to :location, optional: true
end
shrinerb initializer:
require "shrine"
require "shrine/storage/file_system"
if Rails.env.production?
require "shrine/storage/google_cloud_storage"
# Configure Shrine to use Google Cloud Storage in production
else
# Use local file system storage in development and test environments
Shrine.storages = {
cache: Shrine::Storage::FileSystem.new("public", prefix: "uploads/cache"), # temporary
store: Shrine::Storage::FileSystem.new("public", prefix: "uploads/store"), # permanent
}
end
# Common Shrine plugins and configurations
Shrine.plugin :activerecord
Shrine.plugin :cached_attachment_data # for retaining the cached file across form redisplays
Shrine.plugin :restore_cached_data
Shrine.plugin :refresh_metadata
Shrine.plugin :store_dimensions
Shrine.plugin :determine_mime_type, analyzer: :marcel
Shrine.plugin :metadata_attributes # for persisting metadata
Shrine.plugin :derivatives
Shrine.plugin :metadata_attributes, filename: :filename
image_uploader:
require "shrine"
class ImageUploader < Shrine
# Plugin configurations and custom logic here
end
What I expect:
-Shrinerb to be able to handle the metadata, specifically the filename
from upload to storage cache, to storage store(permanent).
What I am seeing:
-Filepond is providing the metadata and once its handed off the shrinerb the filename is not sticking.
I am assuming this is an issue with shrinerb itself. I am using gem 'shrine', '~> 3.5'