In this Ruby on Rails tutorial, we are going to configure Ruby on Rails Active Storage module to work with Google Cloud Platform, Amazon AWS S3 Buckets, and Microsoft Azure Cloud.
Table of contents
Let us learn more about Ruby on Rails Active Storage setup...
...or have it done
Yes, Hix does this - so you don't have to.
Ruby on Rails Active Storage is responsible for storing any files in the Ruby on Rails application and exposing them to Ruby on Rails application's Active Record objects.
Ruby on Rails Active Storage out of the box comes equipped with four different file storage options:
and on top of that, supports mirroring files between multiple storage destinations for sane migrations and backups.
Furthermore, Ruby on Rails Active Storage equips the application into the ability to perform various file transformations:
Ruby on Rails Active Storage is the module to use whenever in need to do any kind of work on files.
If your Ruby on Rails application needs to store an avatar uploaded by a user in order to easier identify him in your web app, use Ruby on Rails Active Storage module.
If your Ruby on Rails application needs to generate payment invoices in order to later send them via email, use Ruby on Rails Active Storage module.
In order to work, Ruby on Rails Active Storage requires two tables in your application's database:
active_storage_blobs
table,active_storage_attachments
tableIn order to acquire Ruby on Rails migrations creating those tables and then create them in your Ruby on Rails application, run
rails active_storage:install rails db:migrate
Ruby on Rails Active Storage supports declaring multiple services configuration usage, with an ability to keep multiple storage services mirrored.
The Ruby on Rails Active Storage configuration file bases on two special keys in order to synchronize files between multiple storage services:
primary
accepting the predefined service name as a value,mirrors
accepting an array of predefined service names as a value,This is especially useful in order to safely migrate between services in the production environment of the Ruby on Rails application with zero downtime.
While configuring Ruby on Rails Active Storage in your application, you are going to be interested in the following files.
On top of the default Ruby on Rails environments, any other environment configuration file that your application defines, such as for example config/environments/staging.rb, is going to configure the Ruby on Rails Active Storage module.
Let us take a look at the most basic configuration for the Ruby on Rails Active Storage module - the simple server disk usage.
This is the default configuration that comes with Ruby on Rails project intialization.
config/storage.yml
local: service: Disk root: <%= Rails.root.join("storage") %> test: service: Disk root: <%= Rails.root.join("tmp/storage") %>
The example Ruby on Rails Active Storage file defines two services, local and development.
Both of them save files to defined Ruby on Rails application directories, let's make sure they are created in your project root.
cd /path/to/rails/app mkdir files mkdir -p tmp/files
This should be optional unless your Ruby on Rails application was initialized with the --skip-active-storage
configuration option.
The test service takes advantage of the temporary directory, that's usually ignored by git version control in the .gitignore file.
The disk service is the one that you'd probably want to use in the development and potentially in the production environment.
It would also go to the .gitignore file, yet you wouldn't want to lose it on production - anyway, make sure its there for the development process.
.gitignore
/storage/* /tmp/*
Let's now take a look at the Ruby on Rails Active Storage environment configuration file - let it be the test one, as it will most likely look like in most of Ruby on Rails applications.
config/environment/test.rb
config.active_storage.service = :test
This simple configuration option accepts a symbol representing the service name previously defined in the Ruby on Rails Active Storage configuration file.
In our case, it tells Ruby on Rails Active Storage module to write to the temporary files directory while running the app in the test environment.
Configuration of other environments' Ruby on Rails Active Storage module is going to look like that:
config/environment/production.rb, config/environment/development.rb
config.active_storage.service = :local
And that's pretty much it.
Continue reading in order to learn how to use third-party cloud storage services with Ruby on Rails Active Storage module.
Google Cloud Platform Storage service connection is easily configurable with Ruby on Rails Active storage module.
The most difficult part of the process is not Ruby on Rails code-related - yet still worth automating with Hix on Rails - but the whole setup on the Google Cloud Platform part.
Let's get through it.
In order to use Google Cloud Storage with Ruby on Rails Active Storage module, we need to create an account first. Follow these steps in order to do that.
You are now on your Google Cloud Platform dashboard dedicated to Storage management. By default, Google Cloud Platform creates an entity called "My First Project".
For the purposes of this guide, we are going to use it, but in your Ruby on Rails production projects, it's worth creating a project with a more meaningful name than that.
Now that we've created the Google Cloud Platform account and our first bucket in the Storage service, let's get through the authorization part.
Follow the credentials generation process in order to authorize Ruby on Rails Active Storage to connect to Google Cloud Storage.
Now that we've successfully obtained the Google Cloud Storage JSON credentials private key, let's connect our Ruby on Rails Active Storage using it.
For Ruby on Rails Active Storage to work with Google Cloud Storage there's a dedicated gem required to be installed.
Add the following to your Ruby on Rails application Gemfile file.
Gemfile
gem 'google-cloud-storage'
Next, open the downloaded Google Cloud Storage JSON file with a text editor of your choice.
keyfile.json
{ "type": "service_account", "project_id": "40hallowed-ridge-264013", "private_key_id": "32976f16b04ece6a6fb8bc3bb4c52ea48f738bb8", "private_key": "-----BEGIN PRIVATE KEY-----\n<.....>\n-----END PRIVATE KEY-----\n", "client_email": "hix-on-rails@40hallowed-ridge-264013.iam.gserviceaccount.com", "client_id": "102135739378581270686", "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://oauth2.googleapis.com/token", "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/hix-on-rails%40hallowed-ridge-264013.iam.gserviceaccount.com" }
Ruby on Rails Active Storage supports two types of configuration for the Google Cloud Storage service.
The first way to configure Ruby on Rails Active Storage to connect with your Google Cloud Storage bucket is by using the credentials
key, which accepts a path to the JSON credentials file stored in your Ruby on Rails application directory.
config/storage.yml
google: service: GCS credentials: <%= Rails.root.join("path/to/keyfile.json") %> project: "My First Project" bucket: "hix-on-rails-active-storage"
The second option is to pass each of the configuration options defined in the Google Cloud Storage JSON file separately.
config/storage.yml
google: service: GCS credentials: type: "service_account" project_id: "hallowed-ridge-264013" private_key_id: "32976f16b04ece6a6fb8bc3bb4c52ea48f738bb8" private_key: "-----BEGIN PRIVATE KEY-----\n<.....>\n-----END PRIVATE KEY-----\n" client_email: "hix-on-rails@hallowed-ridge-264013.iam.gserviceaccount.com" client_id: "102135709378581270686" auth_uri: "https://accounts.google.com/o/oauth2/auth" token_uri: "https://accounts.google.com/o/oauth2/token" auth_provider_x509_cert_url: "https://www.googleapis.com/oauth2/v1/certs" client_x509_cert_url: "https://www.googleapis.com/robot/v1/metadata/x509/hix-on-rails%40hallowed-ridge-264013.iam.gserviceaccount.com" project: "My First Project" bucket: "hix-on-rails-active-storage"
In both cases, it is not the best idea to keep any secrets in the version control system. Let's install the dotenv-rails gem instead and put all the configuration into the dedicated .env file.
.env
GCS_PROJECT_ID=hallowed-ridge-264013 GCS_PRIVATE_KEY_ID=32976f16b04ece6a6fb8bc3bb4c52ea48f738bb8 GCS_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n<.....>\n-----END PRIVATE KEY-----\n" GCS_CLIENT_EMAIL=hix-on-rails@hallowed-ridge-264013.iam.gserviceaccount.com GCS_CLIENT_ID=102135709378581270686 GCS_AUTH_PROVIDER_X509_CERT_URL=https://www.googleapis.com/robot/v1/metadata/x509/hix-on-rails%40hallowed-ridge-264013.iam.gserviceaccount.com GCS_PROJECT="My first project" GCS_BUCKET=hix-on-rails-active-storage
After doing that, simply use all the environment variables in the Ruby on Rails Active Storage configuration file.
config/storage.yml
google: service: GCS credentials: type: "service_account" project_id: <%= ENV['GCS_PROJECT_ID'] %> private_key_id: <%= ENV['GCS_PRIVATE_KEY_ID'] %> private_key: <%= ENV['GCS_PRIVATE_KEY'] %> client_email: <%= ENV['GCS_CLIENT_EMAIL'] %> client_id: <%= ENV['GCS_CLIENT_ID'] %> auth_uri: "https://accounts.google.com/o/oauth2/auth" token_uri: "https://accounts.google.com/o/oauth2/token" auth_provider_x509_cert_url: "https://www.googleapis.com/oauth2/v1/certs" client_x509_cert_url: <%= ENV['GCS_CLIENT_X509_CERT_URL'] %> project: <%= ENV['GCS_PROJECT'] %> bucket: <%= ENV['GCS_BUCKET'] %>
This way your Google Cloud Storage credentials are not stored in the repository holding your Ruby on Rails application code and are less likely to get stolen.
Amazon Web Services AWS S3 storage service connection is easily configurable with Ruby on Rails Active Storage module.
The most difficult part of the configuration is the whole setup on the Amazon Web Services AWS S3 part - yet it is still worth it to automate Ruby on Rails Active Storage configuration with Hix on Rails.
Let's dive into it.
Get through the following steps in order to create your Amazon account for connecting Ruby on Rails Active Storage with the AWS S3 service.
Now that you've created your AWS account, let's create the Amazon S3 bucket.
Follow the steps below in order to do that.
The last step for Ruby on Rails Active Storage module towards accessing your Amazon AWS S3 bucket is obtaining your account credentials.
Let's see how to do that.
With regard to the AWS Best Practices, we are going to create a special user for our Ruby on Rails Active Storage module, with access specifically set to the Amazon AWS S3 service only.
The Amazon access can be modified at any point for given users.
Follow the steps below.
Now that we've obtained Amazon AWS S3 credentials, let's finalize connecting the Ruby on Rails Active Storage module to our freshly created AWS S3 bucket.
Ruby on Rails Active Storage module is able to connect with your Amazon AWS S3 service thanks to aws-sdk-s3
gem.
Open your project's Gemfile file and add the following.
gem 'aws-sdk-s3'
Now, let's get to the Ruby on Rails Active Storage configuration.
Browse a full list of AWS regions in order to find your S3 bucket region code.
config/storage.yml
s3: service: S3 access_key_id: "AKIAIOSFODNN7EXAMPLE" secret_access_key: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" region: "eu-west-2" bucket: "hix-on-rails"
Adjust the Ruby on Rails Active Storage configuration file with your Amazon AWS S3 credentials.
A better way to store Ruby on Rails application credentials is by using the dotenv-rails
gem. After installing it, create the .env file and add the following.
.env
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY AWS_BUCKET=hix-on-rails AWS_REGION=eu-west-2
The next step is to load those environment variables into the Ruby on Rails Active Storage configuration file.
config/storage.yml
s3: service: S3 access_key_id: <%= ENV['AWS_ACCESS_KEY'] %> secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %> region: <%= ENV['AWS_REGION'] %> bucket: <%= ENV['AWS_BUCKET'] %>
This way you don't store any secrets in your Ruby on Rails project's version control system - other supported ways to achieve the same goal are using different configuration methods of the AWS Ruby SDK package.
Microsoft Azure Blob Storage service connection is easily configurable with Ruby on Rails Active Storage module.
Once you get through the Microsoft Azure Blob Storage account creation and setup, it is worth to automate the Ruby on Rails Active Storage configuration with Hix on Rails.
Let's rock.
For Ruby on Rails Active Storage to work with Microsoft Azure Storage, the Microsoft account and Microsoft Azure account are needed.
Follow the steps below in order to create a Microsoft account.
Now that we have created the Microsoft account, we are going to create the Microsoft Azure account related to it.
You should be redirected to the form presented below.
That's it, both Microsoft accounts required by Ruby on Rails Active Storage are ready to use.
In the new account, let's create the "Storage account" and an entity that's specific to Azure, called "Container", which is an equivalent to AWS S3 and Google Cloud Storage "Bucket".
With all this in place, let's collect the final piece required for Ruby on Rails Active Storage to work with our Microsoft Azure account.
The last step toward working Ruby on Rails Active Storage module reading and writing files to our Microsoft Azure Storage service is obtaining its credentials.
In order to do that, in the left-hand sidebar "Settings" section navigate to the first section named "Access keys".
Leave this page open for the Ruby on Rails Active Storage configuration described in the next step.
In order to work, Ruby on Rails Active Storage requires the dedicated gem.
Open your Gemfile and add the following.
gem 'azure-storage-blob'
The next step is to edit the Ruby on Rails Active Storage configuration file.
config/storage.yml
azure: service: AzureStorage storage_account_name: "hixonrails" storage_access_key: "12id12dni1ksld1niodnio1dn1opdm1skdm1idmop1wm1pdm1pd1" container: "activestorage"
The more secure way to store your Microsoft Azure Storage credentials is to use dotenv-rails
gem instead of keeping them in the Ruby on Rails Active Storage configuration file, which is checked into the git version control system.
.env
AZURE_STORAGE_ACCOUNT_NAME=hixonrails AZURE_STORAGE_ACCESS_KEY=12id12dni1ksld1niodnio1dn1opdm1skdm1idmop1wm1pdm1pd1 AZURE_STORAGE_CONTAINER=activestorage
With this saved, edit the Ruby on Rails Active Storage configuration file.
config/storage.yml
azure: service: AzureStorage storage_account_name: <%= ENV['AZURE_STORAGE_ACCOUNT_NAME'] %> storage_access_key: <%= ENV['AZURE_STORAGE_ACCESS_KEY'] %> container: <%= ENV['AZURE_STORAGE_CONTAINER'] %>
This way your Ruby on Rails application is one step closer to respect Twelve-Factor App methodology.
Ruby on Rails Active Storage configuration is as easy as it gets - all you need to do is filling your access data to the Cloud Storage provider of your choice.
It gets even easier if you decide that your Ruby on Rails Active Storage module is going to store the files on your server's disk.
The difficult, yet in case of most of the organizations one-time part of the Ruby on Rails Active Storage configuration is the account creation and setup with the Cloud Storage provider of your choice - Amazon, Google or Microsoft.
In order to make the Ruby on Rails Active Storage configuration part even easier, consider using Hix on Rails, the Ruby on Rails Application Template that integrates the Active Storage setup in its setup wizard.
Hello hixonrails
I have some troubles with cofiguration gem azure-storage, beacuse when I'm load the creadetials it's working fine, but when I need upload image, it retrive this exception ActiveStorage::IntegrityError.
Thank very much !
Hi Alexis,
I'm pretty sure that your problem is unrelated to the
azure-storage
gem. Check out theActiveStorage#IntegrityError
documentation:Debugging it, to see if it's still raised, I'd go for:
Disk
storageThat'd eliminate the gem.
Wiktor Plaga I appreciate your answer, but I figured out fixed the error, it was a dumb error. I must to create the file container before upload image that's it.
That's great Alexis, I'm happy you got it done. Keep up the good work :).