filename not populating in image_data in rails 7 with filepond
kbachand opened this issue · comments
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'
When you receive a POST /location
, I see the uploaded file data being sent in file
param (which includes the filename), but I don't see the controller actually using that data to form an uploaded file object. It only seems to use uploaded file IDs and refreshes the metadata, which won't retrieve the original filename, as it's not stored on the storage service.
So, the reason the original filename is getting lost is because you're not passing it all the way through.