Rails 5.2 added a built-in solution for handling file uploads using Active Storage.
Let’s say, we have an Candidate model that has two attachments resume and
cover_letter.
class Candidate < ApplicationRecord
has_one_attached :resume
has_one_attached :cover_letter
end
# Attach cover_letter to the candidate.
candidate = Candidate.last
candidate.cover_letter.attach(
io: File.open("path/to/cover_letter"),
filename: "cover_letter.txt",
content_type: "text/plain"
)Before Rails 6.1, only one cloud storage service (Amazon S3, Google cloud storage, Microsoft Azure storage) could be used for overall application.
But, there could be cases where our application might require to upload images to different storage services.
In Rails 6.1
For the above example, let’s say we want to upload resume to Amazon S3
and cover_letter to Google cloud.
We need to pass service parameter to has_one_attached method as shown
below:
class Candidate < ApplicationRecord
has_one_attached :resume, service: :amazon
has_one_attached :cover_letter, service: :google
endIn the above example, resume of the candidate is stored to amazon and cover_letter
to google.
storage.yml can be configured as below for multiple storage services:
test:
service: Disk
root: <%= Rails.root.join("tmp/storage") %>
local:
service: Disk
root: <%= Rails.root.join("storage") %>
amazon:
service: s3
access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
region: <%= Rails.application.credentials.dig(:aws, :aws_region) %>
bucket: <bucket_name>
google:
service: google_cloud
project: <project_name>
credentials: <%= Rails.root.join("path/to/gcs.keyfile") %>
bucket: <bucket_name>NOTE:
-
If the
serviceis not specified the defaultserviceset inconfig/environmentsis used for storage. -
If specified service is not properly configured,
has_one_attachedwould throw an error. -
If our project is already using Active Storage and when we upgrade to Rails 6.1, we should run
rake app:updateto make sureservice_namecolumn is added to the internalActiveStorageBlobmodel.
