Skip to main content
Common Features:

User Avatars with ActiveStorage

29

Episode 272 · November 21, 2018

Adding user avatars is pretty easy using Rails' ActiveStorage feature. We'll be using Devise in this example, but this applies to any user authentication system.

Basics Models Authentication File Uploading ActiveStorage


Transcripts

User Avatars with Rails Active Storage

In this episode I'm going to show you a quick way to add avatars to your Rails application using ActiveStorage and Devise.

We're going to start up a new Rails application using the Jumpstart template. This is going to take care of pre-installing Bootstrap and Devise for us, so we won't have to fiddle with those gems and can just focus on the avatars.

So let's start up a new rails app named, appropriately, avatars, and run the appropriate generator:

    rails new -m template.rb avatars
    cd avatars
    rails active_storage:install
    rails db:migrate

Running the ActiveStorage generator will provide the application with the database migration to create the necessary tables for ActiveStorage.

If you aren't using the Jumpstart template, then at this point you would also need to install Devise, set up the User model and install the Devise views so they can be customized:

    rails g devise:install
    rails g devise User
    rails g devise:views

Let's start customizing those views now. In the registrations edit view, just before the Full Name field, we're going to add a new field:

app/views/devise/registrations/edit.html.erb

    <div class="form-group">
        <div class="row">
            <div class="col-sm-4">
                <% if resource.avatar.attached? %>
                    <%= image_tag resource.avatar.variant(resize: "100x100!"), class: "rounded-circle" %>
                <% else %>
                    <%= image_tag garavatar_iamge_url(current_user.email, size: 100), height: 100, width: 100, class: "rounded-circle" %>
                <% end %>
            </div>
            <div class="col-sm-8">
                <%= f.file_field :avatar %>
            </div>
        </div>
    </div>

You could wrap this in Bootstrap classes if you felt so inclined for additional styling. But what we're really interested in doing is displaying either the User's avatar or a default from gravatar if the User doesn't have an avatar yet. (The Jumpstart template takes care of giving us the gravatar_image_tag gem. If you're not using the template, you'll need to install it.)

Make sure you add the avatar to the User model:

app/models/user.rb

    has_one_attached :avatar

In the Application Controller, you'll want to add these lines if you don't have them. (The Jumpstart template takes care of giving them to us already.)

app/controllers/application_controller.rb

    before_action :configure_permitted_parameters, if: devise_controller?

    protected

    def configure_permitted_parameters
        devise_parameters.sanitizer.permit(:account_update, keys: [:name, :avatar])
    end

What this is doing is making Devise accept the name and avatar fields as valid inputs, since they aren't fields that Devise accepts out of the box.

With all of this set up, start up the Rails application, and visit the Sign Up page to create a new account to test this out.

Assuming the email address you sign up with has a gravatar image associated with it, once you are logged in you should see that image displayed as your avatar.

Visiting the account edit screen will also provide the file picker element that will allow you to upload a new Avatar to use instead of the default from gravatar.

If you don't have any avatar images handy for testing this out to see how it all works, you can visit UI Faces, which has a wide selection of avatar images available.

Now anywhere in the application where you are going to want to display the avatar is going to need code very similar to what we did in the view above. This calls for some refactoring, pulling that code out into a helper method.

app/helpers/application_helper.rb

    def user_avatar(user, size=40)
        if user.avatar.attached?
            user.avatar.variant(resize: "#{size}x#{size}!")
        else
            gravatar_image_url(user.email, size: size)
        end
    end

Now we have a generic helper method that handles all of the logic to figure out which avatar image to display. So we can go back to the view and update it to use the helper:

app/views/devise/registrations/edit.html.erb

    <div class="form-group">
        <div class="row">
            <div class="col-sm-4">
                <%= image_tag user_avatar(resource, 100), class: "rounded-circle" %>
            </div>
            <div class="col-sm-8">
                <%= f.file_field :avatar %>
            </div>
        </div>
    </div>

If you go back to the application and reload the page we shouldn't see any changes to the application, which is a good thing.

The last thing we want to do is update our nav bar to use this new helper to display the avatar of the logged in user. Open up the navbar partial, and replace the gravatar image_tag line with:

/app/views/shared/_navbar.html.erb

    <%= image_tag user_avatar(current_user, 20), class: "rounded-circle" %>

Return to the application and refresh the page, and the uploaded avatar should now display in the navbar instead of the gravatar image.

Now we have working avatars that we can use anywhere in our application: gravatar by default, or the uploaded image provided by a User.

If you want to change where the images are stored you can use any of the ActiveStorage functionality to upload images to Amazon S3, DigitalOcean Spaces, Google Cloud Storage, or Azure.

By default these images will be stored to disk so keep that in mind. Storing the images to disk is generally fine for development, but in production you will want to upgrade to one of the above mentioned options.

To do that you'll need to obtain the requisite keys to configure your chosen storage option in config/storage.yml. Then you need to configure the production environment to use them:

config/environments/production.rb

Replace this:

    config.active_storage.service = :local

With this (assuming your chosen image storage solution is Amazon S3)

    config.active_storage.service = :amazon

With ActiveStorage, adding images to our Rails application is pretty easy. We don't have to think about changes to our database in order to add images, because ActiveStorage handles all of that for us.

Loading...

Subscribe to the newsletter

Join 27,623+ developers who get early access to new screencasts, articles, guides, updates, and more.

    By clicking this button, you agree to the GoRails Terms of Service and Privacy Policy.

    More of a social being? We're also on Twitter and YouTube.