Azure Blob Storage is an object storage service that is very similar to AWS S3. ActiveStorage from Rails has built-in support for both ActiveStorage and S3 for file storage, making it easy to integrate and even swap out providers.
The Honeybadger Blog has already explored using S3 for file storage in Rails, and in this article, we'll explore using Azure to allow users to upload files in a Rails application. You can find the final code here on Github.
Author's note about the azure-storage-blob
gem
This tutorial uses the azure-storage-blob
Ruby gem to integrate ActiveStorage with Azure. While the official Rails guides still recommend this gem, it's no longer supported by Microsoft.
If you're not comfortable using an unsupported Gem, consider using another cloud provider or even writing your own integration that uses the Azure Storage REST API directly.
Setup in Azure
Azure Blob Storage is priced based on how much data you store and how often you need to access it. Regardless, the free credits will suffice for this tutorial. Create an account on the Azure Portal, then proceed to the main page of the Azure Portal. You'll be greeted with a number of services, but we're only interested in blob storage today.
A screenshot of the Azure Portal Homepage
Under services, select "Storage Accounts." If you can't find it, you can search for it in the top search bar. Unless you're using an account with an already active subscription, you'll be prompted to set up a free trial or payment for pay-as-you-go.
Once you're on the Storage Accounts page, select "New" to create a new storage account. You'll be prompted to select a subscription, then a resource group. A resource group logically connects related resources in Azure, so you'll likely want to create a new one. I named mine event-tracker
, after the app that we'll integrate with, in the next section.
The Azure portal new storage account page
You'll also need a name for the storage account you're creating. I named mine after my application, so it's easy to find in the portal as the storage resource for my event-tracker app.
You'll also be prompted for performance and redundancy settings. This is heavily application-dependent, but I chose "Standard" and "LRS," respectively, for this tutorial, as they're the cheapest options.
If you don't need any custom configuration, click "Review" and then "Create" to spin up your storage service. Once your deployment is complete, select "Go to resource."
In the menu on the left of the dashboard, select "Containers," then select the "+ Container" button. Give your new container a meaningful name, then select "Create."
Now that you have an Azure account, a blob storage service, and a container in that storage service, you're finally ready to note your keys, which your application will use to authenticate with Azure. In the menu on the left of your screen, select "Access Keys." On either key, copy the key, not the connection screen. You'll need this in the next section, so keep it handy but secure.
If you found all the configuration tedious, you may be interested in using Terraform to manage your Azure resources. Terraform comes with its own challenges, but it makes changes more trackable, and managing infrastructure as code is an increasingly preferred trend.
Configuring ActiveStorage
Rails makes handling files easy with ActiveStorage, a library built for exactly this. It allows you to configure your provider and is compatible with both Azure Blob Storage and AWS S3. making it important to understand when to use Azure Blob Storage for your specific needs.
Building a simple example application
We'll quickly go over building a simple CRUD application in Rails that we can use to demonstrate file uploads. If you're adding blob storage to an existing application, feel free to skip this section!
To start, we'll create a new Rails app with a specific version:
rails _7.1.1_ new event-tracker
Assuming that was successful, go into the new application directory:
cd event-tracker
Now, we'll generate scaffolds for a resource we'll use later for attaching files. For this example, we'll make an "Event":
rails generate scaffold Event title:string date:datetime
Finally, we'll run the created database migration to create the necessary Events
table next with:
rails db:migrate
With this, we have the code needed to create, read, update, and delete events from our database. To see the code in action, run the rails server and visit localhost:3000/events
in your browser.
How to set up Azure Blob Storage for ActiveStorage
Since we'll be using ActiveStorage to do all our file uploading, we'll need to configure it for our Azure service. First, install the Azure gem by adding the following to your Gemfile:
gem "azure-storage-blob"
Then:
bundle install
The first file you'll need to make changes in is config/storage.yml
. You'll want to uncomment the microsoft
section and paste in your account and container name from when you created the container in the Azure portal. You'll also change microsoft
to azure
You could paste in your storage_access_key
, but it's a better idea to not put production secrets in git repositories.
Fortunately, the Rails credentials manager can handle that secret for you. Simply paste in your account and container names, and leave the call to Rails.application.credentials.dig
- we will put our access key into the credential manager in just a bit. Below is my config/storage.yml
. The only thing I have changed is to uncomment the microsoft
section, rename it to azure
, and paste in the storage_account_name
and container
:
test:
service: Disk
root: <%= Rails.root.join("tmp/storage") %>
local:
service: Disk
root: <%= Rails.root.join("storage") %>
# Use bin/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: us-east-1
# bucket: your_own_bucket-<%= Rails.env %>
# Remember not to checkin your GCS keyfile to a repository
# google:
# service: GCS
# project: your_project
# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %>
# bucket: your_own_bucket-<%= Rails.env %>
# Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key)
azure:
service: AzureStorage
storage_account_name: eventtrackerstorage1
storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %>
container: event-tracker-container1
# mirror:
# service: Mirror
# primary: local
# mirrors: [ amazon, google, microsoft ]
Next, you have to configure ActiveStorage to use azure
for storage while in production. In config/environments/production.rb
, look for the line that says config.active_storage.service
and set it to equal :azure
:
config.active_storage.service = :azure
If you're unsure how to connect to Azure Blob Storage, you'll need to follow the setup steps mentioned in the first section of the article to obtain the necessary credentials and endpoint information from the Azure portal. You'll likely want to continue to use local storage when running the app locally so you don't pollute your production Azure container with test data. If you'd like to have your local instance of the app also use Azure, you'll need to make the same setting as above in config/environments/development.rb
.
Setting your Azure key in Rails encrypted credentials
You'll need to set the credentials in Rails encrypted credential manager so that when your config file sees Rails.application.credentials.dig(:azure_storage, :storage_access_key)
, it evaluates to your Azure key. The credentials manager uses the key in a file called master.key
to encrypt and decrypt the values, so there are several ways to edit the credentials. One of the simplest is to use vim. In your terminal, run:
EDITOR=vim bin/rails credentials:edit
Next, type 'i' on your keyboard to allow you to insert characters. Insert a key for azure_storage
, then a nested key for storage_access_key
with the value you previously copied from the Azure portal.
azure_storage:
storage_access_key: super-secret-value
Next, save the file and exit vim - you can do this by typing ESC, then :wq
followed by the enter key.
Lastly, setup ActiveStorage database tables with:
rails active_storage:install
Then run the migration with:
rails db:migrate
Reading and writing from the Rails application
Now that we have ActiveStorage ready to use Azure, it's time to put it to use. Earlier, we generated a scaffold for creating, reading, updating, and deleting event objects. We gave the event object properties for title and date, but nothing else. This application would be much more useful if we allowed users to attach files to events, wouldn't it?
In the events model, app/models/events.rb
, add the following line:
has_one_attached :notes
Next, edit the form for notes to include a field for uploading the file. In app/views/events/_form.html.erb
, add the following inside of the form_with
block:
<div>
<%= form.label :notes, style: "display: block" %>
<%= form.file_field :notes %>
</div>
Next, permit the new file field in the events controller. In app/controllers/events_controller.rb
, change the event_params
method to include the new parameter:
def event_params
params.require(:event).permit(:title, :date, :notes)
end
Finally, run the rails server and visit localhost:3000/events
. Create a new event, and you'll see a field for uploading a file for the event's "Notes."
The event form with file upload
Now, when you create an event and attach a file for "notes," the file will be stored in Azure. You can confirm its existence in Azure by viewing the contents of your storage container in the Azure portal.
This feature is only useful to the user if they can later access the file, so we'll add that now. In app/view/events/_event.html.erb
, add the following to display a hyperlink to the notes underneath the date:
<p>
<strong>Notes:</strong>
<a href="<%= event.notes.url %>"><%= event.notes.filename %></a>
</p>
Now, when viewing a note, you'll see a hyperlink with the filename that leads to the file stred in Azure.
The event show page with linked file
Shipping Rails apps with Azure blob storage
Integrating Azure Blob Storage with Ruby on Rails using ActiveStorage is a straightforward and effective way to manage file uploads in a Rails application. The steps outlined in this article demonstrated setting up Azure Blob Storage, configuring ActiveStorage, and integrating the storage service into a Rails application.
This integration not only streamlines the process of managing file uploads but also highlights the adaptability of Ruby on Rails in working seamlessly with different cloud storage providers. Whether you're building a new application or enhancing an existing one, integrating Azure Blob Storage with Rails presents a scalable and secure solution for powering your application's file storage features.
If you found this article helpful, sign up for theĀ Honeybadger newsletter to get notified when we publish more helpful tutorials like this!