Today DHH announced Active Storage: a new gem that makes it easy to attach Amazon S3 or Google Cloud Storage files to Active Record model instances. Looks like this is slated to become part of Rails in 5.2. I happen to have a Rails 5.2 application with a user model around, so here's a quick look at adding an avatar to that model with Active Storage.

NOTE: This is early days for this library, so don't count on this post to be perfectly accurate if you're reading it months from now.

1. Add the gem to your Gemfile and run bundle install

gem 'activestorage', github: 'rails/activestorage'

2. Add require "active_storage" to config/application.rb.

3. Run rails activestorage:install. This will create the storage and tmp/storage directories in your application, copy a default configuration file to config/storage_services.yml, and create a new migration. The migration will build the active_storage_blobs and active_storage_attachments tables in your database.

4. Run rails db:migrate

NOTE: I had to change the class name in the migration from ActiveStorage::CreateTables to ActiveStorageCreateTables to get it to run without errors.

5. Add config.active_storage.service = :local to your development.rb file. This will use the preconfigured local-file storage when you're in the development environment.

6. Tell your User model that it has an attached file:

class User < ApplicationRecord
  has_one_attached :avatar
  ...
end

7. Make a copy of your config/storage_services.yml file to config/storage_services_backup.yml. Then delete the amazon, google, and mirror sections from the original file. Otherwise, your server won't start, because it will be looking for keys and files that don't exist.

8. Add a field to your user edit form to input an avatar file:

<%= f.file_field :avatar, class: "form-control" %>

9. Add a control to your user show view to display the avatar:

<%= image_tag(@user.avatar.url) %>

10. Update your users controller to attach the file:

  def update
    @user = User.find(params[:id])
    avatar = params[:user][:avatar]
    if @user.update(user_params)
      if avatar
        @user.avatar.attach(avatar)
      end
      redirect_to @user, notice: "Your profile has been updated"
    else
      render 'edit'
    end
  end

11. Restart your application and navigate to /users/<id>edit to edit an existing user. Select a file and save the change. You should see the avatar image displayed on the edited user.

Of course, in production you'll want to use an actual cloud service. If you check your backed-up configuration file you'll see how to set up the keys for either S3 or AWS. Then it should just be a matter of setting the appropriate configuration in production.rb (note that I haven't tried this yet!)