Custom Direct Uploads Controller
- active_storage
Active Storage มาพร้อมกับฟีเจอร์ Direct Uploads ซึ่งทำให้ client สามารถอัพโหลดไฟล์ขึ้นไป cloud ซึ่งเจ้า Direct Uploads ก็จะผูกกับ service ที่กำหนดไว้
สำหรับ Web Application ที่ใช้งาน S3 ในการจัดเก็บไฟล์ และมีความต้องการในการแยก bucket เป็น 2 อัน ซึ่งอันแรกจะใช้งานแบบ private ส่วนอีกอันจะเป็นแบบ public จะพบปัญหาที่ว่า Direct Uploads นั้นจะถูกผูกอยู่กับ service ที่ได้กำหนดไว้ใน config เท่านั้น ดังสังเกตได้จาก code ด้านล่าง
# https://github.com/rails/rails/blob/main/activestorage/lib/active_storage/engine.rb
initializer "active_storage.services" do
ActiveSupport.on_load(:active_storage_blob) do
...
if config_choice = Rails.configuration.active_storage.service
ActiveStorage::Blob.service = ActiveStorage::Blob.services.fetch(config_choice)
end
end
end
จากที่ได้เข้าไปศึกษาโค้ดของ Active Storage ก็พบว่า ActiveStorage::Blob
นั้นสามารถรับ service_name
เพื่อเลือก service ที่จะใช้งานตอนที่จะสร้าง Model ได้
# https://github.com/rails/rails/blob/main/activestorage/app/models/active_storage/blob.rb
def create_before_direct_upload!(key: nil, filename:, byte_size:, checksum:, content_type: nil, metadata: nil, service_name: nil, record: nil)
create! key: key, filename: filename, byte_size: byte_size, checksum: checksum, content_type: content_type, metadata: metadata, service_name: service_name
end
ดังนั้นวิธีการง่ายๆ ที่ใช้ตอนนี้ก็คือการสร้าง Custom Controller ที่กำหนด service_name
ที่จะใช้แยกออกมา และกำหนด route
เพื่อใช้ Direct Uploads ไฟล์เข้าไปยัง public_bucket
ใหม่ขึ้นมา
class CustomDirectUploadsController < ActiveStorage::DirectUploadsController
def create
blob = ActiveStorage::Blob.create_before_direct_upload!(**blob_args.merge(service_name: :public_bucket))
render json: direct_upload_json(blob)
end
end
และในฝั่งของ client ก็เพียงเปลี่ยน URL ให้ตรงกับ route
ใหม่ เราก็สามารถที่จะอัพโหลดไฟล์แยกไปยังอีก bucket หนึ่งได้