DEV Community

marisa saunders
marisa saunders

Posted on

How to setup active storage w/ AWS S3

For my final project at Flatiron School we had to add some new technology to our project that we had never used or learned about before and I decided on using Active Storage with AWS S3 to allow a user to upload an avatar. Upon researching, reading blogs, documentation, and watching online tutorials I found that I was having to use many different resources just to figure out how to get started, and therefor have decided to write a step by step tutorial all in one place for whoever needs to get started with Active Storage.

Active Storage setup

First things first, I recommend reading the active storage documentation in rails or at least referencing it if you find that you are having any issues: https://guides.rubyonrails.org/active_storage_overview.html

but I will lay out the necessary steps for you here as well.

  • install "libvips" or "ImageMagick" for image analysis and transformations

  • both of these require the image_processing gem so uncomment it in your Gemfile or add it if you don't see it there already:
    gem "image_processing", ">= 1.2"

  • Active storage uses three tables in your database:
    • active_storage_blobs
    • active_storage_variant_records
    • active_storage_attachments

  • to create these tables run "bin/rails active_storage:install" and after migrate them by running "bin/rails db:migrate"

Here is a photo of my schema file for reference for how yours should look (note please ignore the "photo" column in my users table I had this here as a temporary column for when I was working on the project before I had implemented Active Storage)

Image description

  • Declare active storage services in "config/storage.yml"

Image description

In "config/environments/development" tell Active Storage which service to use
config.active_storage.service = :local

To use the S3 service in production add this line of code to "config/environments/production"
config.active_storage.service = :amazon

To use the test service add this line of code to "config/environments/test"
config.active_storage.service = :test

Setting up your Models, Controllers, and Serializers

Since I was adding the ability for a user to upload an avatar when creating an account I added the following line of code to my user model:
has_one_attached :image

this line of code is very important and establishes the association, do not be confused that this will not be reflected as a column in your schema file

Add the "with_attached_image" method to you Users Controller:

Image description

and make sure to include ":image" into your user params
Image description

Modify your User Serializer like so:

Image description
(adding ":image" to attributes and the "image" custom method)

Setting up AWS

  • make sure your service in config/storage.yml set to "S3"

  • add the "aws-sdk-s3" gem to your gemfile
    gem 'aws-sdk-s3', require: false

Create an AWS account and create a bucket in S3 (you can change your bucket name in "config/storage.yml" to your specific bucket name once we create the bucket, and the region to whatever your specific region once we select it in AWS S3

Once you're logged in click on "S3"
Image description

Click "Create Bucket"
Image description

You will be taken to this page:

Image description

Fill in the form as so:

Bucket name - yourbucketname
AWS Region - your region
Object Ownership - ACLS disables
Block Public Access settings for this bucket - Block all public access
Bucket Versioning - Disable
Tags - leave empty
Default encryption - Server-side encryption w/ Amazon S3 managed keys(SSE-S3)
Bucket Key - Enable

Once you are done click "create bucket"

Click on the name of your new bucket where you will now be taken to a page where you can edit your settings

Click on permissions and scroll to the Bucket Policy section and click on the "edit" button and then the "Policy Generator" button.

Fill out the form as so:

Select Type of Policy - S3 Bucket Policy
Effect - Allow
Principal - arn:aws:iam::ACCOUNT_ID:root
AWS Service - Amazon S3
Actions - DeleteObject, GetObject, PutObject
Amazon Resource Name (ARN) - arn:aws:s3:::BUCKET_NAME/*

  • To find your account ID click your username in the top right corner and your account id will appear

  • you can find your ARN in the properties section of the settings

Image description

Once you have filled out the form click "Add Statement" and "Generate Policy" and copy the Policy JSON Document code that pops up and paste it into the field under Edit Bucket Policy and click "Save Changes" here's a photo of mine for reference:

Image description

Next, go back to your bucket and go to the permissions section where you can scroll down to CORS(Cross-origin resource sharing) and click the "edit" button. Here's mine for reference:

Image description

You can add more methods if you need depending on your app and if you plan to deploy your application you will need to do something like this:

Image description

Now that all of this is saved and complete, click on your username in the top right corner and then click on "security credentials" and then "users" on the left side of the page and click "create user" in the top right corner

Image description

  • The name of the user does not matter or need to be connected to an existing user in your application so I would just name it something generic

Once you enter your user's name click "next" and fill out the form like so:

Permission options - Attach policies directly
Permission Policies - AmazonS3FullAccess

Click "Create User" to save your new user and then click on the name of your new user and then "Security Credentials" where you can scroll down to the Access Keys section and click "Create Access Key"

Select "Application running outside AWS" and add a create description tag called something like "Connect AWS S3 to my_app_name". You will now be able to see your access keys, keep this window open and take a screen shot or download them to a CSV file because once you close this page you wont be able to access them again and you will need them to make connections to your app

In your terminal run: "EDITOR=vim bin/rails credentials:edit"
and edit/update "aws", "access_key_id", and "secret_access_key" with the information in the CSV file you just downloaded after we created the access keys above, once you are done close the file and it will automatically save and you can leave the terminal and you are good to go!

Setting up your Frontend
All of my research led me to use Javascript' formData api as a way to allow the user to upload a photo on the frontend through a form which would then connect to the backend to Active Storage. Here is my signup function and handleSubmit function which is attached to the onSubmit on my form

Image description

  • When working on this project and troubleshooting I made the mistake of adding a header to my POST method so make sure not to do so

Instead of using "e.target.value" like you are most likely using in the rest of your form you will instead need to use "e.target.files" on the image (I am using React Bootstrap if you are confused as to why my form looks like like this)
Image description

If you are using validations in your project I found that the way params was sent back for the image using formData was creating some issues. To resolve this I had to create frontend validations for the image in the form as a workaround to prevent my app from breaking. I am sure there are alternative ways to do this, this is just the option that worked for me. In order to do this I created a new state object:

Image description

and then a conditional statement: "isImage ?" in my form like so:

Image description

Conclusion
I hope this was helpful, of course aspects of this tutorial are specific to my project but I think they can easily be adjusted and manipulated to the specifics of yours. I tried to get into the obstacles and troubleshooting I had to figure out along the way incase you find yourself in the same position!

Top comments (0)