Save image data with AWS_S3 + Ruby on Rails_Active Storage

Overview

When creating an application with Rails, image data is saved in the images folder of assets, but if you use AWS and Rails Active Storage, you can save the image data in the cloud. I'm thinking of deploying my application using AWS, so I've summarized how to use Active Storage to save to AWS S3.

Premise

setup

There is software called ImageMagick that has a function to change the image size in Active Storage, so install it in advance.

python


$ brew install imagemagick

Edit the Gemfile and do a bundle install.

gemfile


gem 'mini_magick', '~> 4.8'

python


$ bundle install

First, install Active Storage and create the active_storage_blobs and active_atorage_attachment tables.

python


$ bin/rails active_storage:install
$ bin/rails db:migrate

Model editing

Add a class method to the model where you want to save the image. The has_one_attached method is used when you want to save one file. Use the has_many_attached method when you want to save multiple files. Also, add model attributes with the attribute method for saving and deleting.

user.rb


has_one_attached :image
Or
has_many_attached :images

attribute :new_image
attribute :remove_image

attribute is a method that can be added as a read / write attribute in the model. I think there are various ways to save the image, but I took the method of saving in the model, so I added the model attribute with the attribute method.

Add before_save in the model.

user.rb


before_save do
  if new_image
    self.image = new_image
  elsif remove_image
    self.image.purge
  end
end

When the image file is saved as described above, if there is new_image, it will be saved, and if there is remove_image, the file will be deleted. Use the purge method to delete the file.

Edit view

Place the file field method on the form.

_form.erb


<%= form.label :new_image %>
<%= form.file_field :new_image %>
<% if @user.image.attached? %>
  <%= image_tag @user.image.variant(resize: "128x128") %>
  <%= form.check_box :remove_image %>
  <%= form.label :remove_image %>
<% end %>

If you have an image file, you can delete it by checking the check box. The variant method of image_tag is a method that can be used only for image files, and you can adjust the size of the image file.

At this point, Active Storage will be used to save the file in the storage directory inside the application method.

AWS settings

Next, create an S3 bucket on AWS. First, create an AWS account. I will omit the detailed setting method, but after creating the root user, create an IAM user and attach a policy (AmazonS3FullAccess) to the IAM user as appropriate. Create an access key for this IAM user and write the access key ID and secret access key to credentials.

terminal


$ EDITOR="vim" rails credentials:edit

:credentials.yml.enc


AWS:
  access_key_id:AWS access key
  secret_access_key:AWS secret access key

Create a bucket as an IAM user. Select the S3 service and create a bucket from the bucket menu. Create a bucket by setting the bucket name, region, etc.

Add the gem to the Gemfile and do a bundle install.

Gemfile


gem 'aws-sdk-s3', require: false

Then edit config/storage.yml. Uncomment the part that says amazon: and fill in the necessary information.

storage.yml


test:
  service: Disk
  root: <%= Rails.root.join("tmp/storage") %>

local:
  service: Disk
  root: <%= Rails.root.join("storage") %>

# Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key)
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:Availability zone with S3
  bucket:Bucket name

Call the access key etc. saved in credentials with Rails.application.credentials.dig (: aws,: ~).

Edit the config/environments/production.rb file.

production.rb


config.active_atorage.service = :amazon

Now you can save the file to S3 in the production environment.

If you edit the same part in the config/environments/development.rb file, you can save it in the S3 bucket in the development environment.

Supplement

When handling multiple files with has_many_attached, you need to be careful about the form settings.

_form.erb


<%= form.label :new_images %>
<%= form.file_field :new_images %>
<% if @user.image.attached? %>
  <% @user.images.each do |image| %>
  <%= image_tag @user.image.variant(resize: "128x128") %>
  <%= form.check_box :remove_image, {multiple:true}, image.id, false %>
  <%= form.label :remove_images %>
<% end %>

When deleting the file, the controller processed it.

users_controller.rb


#abridgement
def update
#abridgement
  if params[:user][:remove_images]
    params[:user][:remove_images].each do |image_id|
      image = @user.images.find(image_id)
      image.purge
    end
  end

Summary

The installation itself was easy, so it was very convenient. I stumbled a lot because I need to be careful when dealing with multiple files. It is one of the systems that I definitely want to incorporate when dealing with files on AWS.

References

Let's use ActiveStorage + AWS S3 with Rails app! [Rails 5.2] How to use Active Storage

Recommended Posts

Save image data with AWS_S3 + Ruby on Rails_Active Storage
Install Ruby on MSYS2 with pacman
Programming with ruby (on the way)
Install ruby on Ubuntu 20.04 with rbenv
Run (provisionally) a Docker image with ShellCommandActivity on AWS Data Pipeline
[Ruby on Rails] Introduction of initial data
[Ruby on Rails] View test with RSpec
Notes on using FCM with Ruby on Rails
[Ruby on Rails] Controller test with RSpec
[Ruby on Rails] Image slideshow using Skippr
[Ruby on Rails] Model test with RSpec
How to implement image posting function using Active Storage in Ruby on Rails
Introducing Rspec with Ruby on Rails x Docker
Publish the app made with ruby on rails
Display Mat type image on GUI with Swing
Update container image with KUSANAGI Runs on Docker
Launch Docker image with initial data injected with docker-compose
(Ruby on Rails6) Creating data in a table
Determine the current page with Ruby on Rails
Scraping yahoo news with [Ruby + Nokogiri] → Save CSV
[Ruby on Rails] Upload multiple images with refile
I made a portfolio with Ruby On Rails