What is Active Storage?
Active storage facilitates uploading files to cloud storage and attaching those files to Active Record objects.
Which storage services are supported?
Amazon S3, Google cloud, Microsoft Azure etc. as well as local disk-based service
Requirements
Various features of Active Storage depend on third-party software which Rails will not install, and must be installed separately:
- libvips v8.6+ or ImageMagick for image analysis and transformations
- ffmpeg v3.4+ for video previews and ffprobe for video/audio analysis
- poppler or muPDF for PDF previews
Image analysis and transformations also require the image_processing gem.
$gem "image_processing", ">= 1.2"
Setup
$rails active_storage:install
$rails db:migrate
This will create 3 tables:
- active_storage_blobs
- active_storage_variant_records
- active_storage_attachments - This is a join table joining model name and attachement for it.
Then update config/storage.yml which defines service names like local: amazon: gcs: digitalocean: etc.
When using certain services, special gems may need to be added e.g. $gem "aws-sdk-s3" etc.
Note: Configuration files that are environment-specific will take precedence: in production, for example, the config/storage/production.yml file (if existent) will take precedence over the config/storage.yml file.
Note: It is recommended to use Rails.env in the bucket names to further reduce the risk of accidentally destroying production data. e.g.
amazon:
service: S3
# ...
bucket: your_own_bucket-<%= Rails.env %>
google:
service: GCS
# ...
bucket: your_own_bucket-<%= Rails.env %>
Then update config/environments/development.rb to specify which service is used for Active storage.
e.g.
# Store files locally.
config.active_storage.service = :local
or
# Store files on Amazon S3.
config.active_storage.service = :amazon
Attaching Files to Records
Use has_one_attached or has_many_attached inside a model. e.g.
Inside Model
class User < ApplicationRecord
has_one_attached :avatar
end
Then inside controller, use
private
def user_params
params.require(:user).permit(:email_address, :password, :avatar)
end
@user.avatar.attach(params[:avatar])
@user.avatar.attached?
Inside Model
class Message < ApplicationRecord
has_many_attached :images
end
Inside Controller
class MessagesController < ApplicationController
def create
message = Message.create!(message_params)
redirect_to message
end
private
def message_params
params.require(:message).permit(:title, :content, images: [])
end
end
@message.images.attach(params[:images])
@message.images.attached?
How to attach images? Add following code to view erb.
<%= form.file_field :document %>
or
<%= form.file_field :documents, multiple: true %>
How to display images?
One attachment
<% if user.document.attached? %>
<%= image_tag user.document %>
<% end %>
Multiple attachements
<% if user.documents.attached? %>
<% user.documents.each do |document| %>
<%= image_tag document %>
<% end %>
<% end %>
How to debug?
$@client.logo.content_type
$@client.logo.content_type
$url_for(@client.logo)
$rails_blob_path(@client.logo, disposition: "attachment")
$rails_blob_path(@client.logo, only_path: true)
I found this Rails Active Storage cheatsheet useful.