Uploading Files to CloudFlare R2 Using Rails ActiveStorage
R2 is a recently launched storage system developed by Cloudflare. It can be compared to Amazon S3 and is compatible with it. However, R2 is designed to be simpler, more affordable, and even offers a free plan with generous benefits. You can find more details about R2 here.
Now, let's learn how to set up R2 with Rails to enable file uploading for this article.
1. Setting Up ActiveStorage
To integrate R2 with Ruby applications, R2 utilizes the AWS Ruby SDK. Therefore, we must install this SDK and an image processing library. To do so, add the following code to your `Gemfile`.
1. Setting Up ActiveStorage
To integrate R2 with Ruby applications, R2 utilizes the AWS Ruby SDK. Therefore, we must install this SDK and an image processing library. To do so, add the following code to your `Gemfile`.
gem "image_processing" gem "aws-sdk-s3", require: false
Run bundle install.
Now, install ActiveStorage by following these steps in the terminal:
1. Run the command:
bin/rails active_storage:install bin/rails db:migrate
2. Set up R2 and create buckets:
- If you haven't already, sign up on Cloudflare and go to your dashboard.
- On the sidebar, click R2, then select "Create Bucket" and give it a name.
- After creating the bucket, navigate to the R2 overview dashboard and click on "Manage R2 API Tokens" at the top right (at the time of writing).
- Create a new API token, give it a name, and select "Edit access" for most permissions.
- Copy the resulting Access Key ID, Secret Access Key, and your Account ID from the top right. We'll use these in the next steps.
3. Set up ActiveStorage:
Configure ActiveStorage for your environments.
Start by adding the Cloudflare credentials to the production environment. In the terminal, run the following command:
bin/rails credentials:edit -e production
Add your Cloudflare credentials, including:
cloudflare: account_id: YOUR_ACCOUNT_ID access_key_id: YOUR_ACCESS_KEY_ID secret_access_key: YOUR_SECRET_ACCESS_KEY endpoint: https://<YOUR_ACCOUNT_ID>.r2.cloudflarestorage.com article_files_bucket: YOUR_ARTICLES_BUCKET_NAME user_files_bucket: YOUR_USERS_BUCKET_NAME
Delete the `config/storage.yml` file and create different `storage.yml` files based on your environments.
In the `config/storage/production.yml` file, include the following for uploading files to R2:
article_files_bucket: service: S3 endpoint: <%= Rails.application.credentials.dig(:cloudflare, :endpoint) %> access_key_id: <%= Rails.application.credentials.dig(:cloudflare, :access_key_id) %> secret_access_key: <%= Rails.application.credentials.dig(:cloudflare, :secret_access_key) %> region: auto bucket: <%= Rails.application.credentials.dig(:cloudflare, :article_files_bucket) %>
You can create a single bucket for all your uploads or separate buckets for different services (e.g., article images, and user avatars). Name them accordingly for clarity.
For example, to also upload user avatars to R2, include the following in the same file as above:
user_files_bucket: service: S3 endpoint: <%= Rails.application.credentials.dig(:cloudflare, :endpoint) %> access_key_id: <%= Rails.application.credentials.dig(:cloudflare, :access_key_id) %> secret_access_key: <%= Rails.application.credentials.dig(:cloudflare, :secret_access_key) %> region: auto bucket: <%= Rails.application.credentials.dig(:cloudflare, :user_files_bucket) %>
In the config/development/storage.yml file, use the following configuration to upload files to local disk storage:
local: service: Disk root: <%= Rails.root.join("storage") %>
In the `config/test/storage.yml` file, configure temporary storage that will be deleted after the tests:
```
test: service: Disk root: <%= Rails.root.join("tmp/storage") %>
```
4. Point your app to use the correct ActiveStorage services:
4. Point your app to use the correct ActiveStorage services:
To specify the default service for file uploads in each environment, add the following code to the respective environment configuration files :
config/environments/production.rb config.active_storage.service = :article_files_bucket config/environments/development.rb config.active_storage.service = :local config/environments/test.rb config.active_storage.service = :test
Finally, in the models where you want to upload files, add the following code:
has_many_attached :images, service: :article_files_bucket
This way, you can upload multiple images for any article, and in production, they will be stored in R2. It's also a good idea to validate the file content types, sizes, and other criteria.