Skip to content
Rails use Active Storage the right way
Ruby HTML CSS JavaScript
Branch: master
Clone or download
Latest commit 2bd0293 Nov 1, 2018
Type Name Latest commit message Commit time
Failed to load latest commit information.
app First commit Nov 1, 2018
bin First commit Nov 1, 2018
config First commit Nov 1, 2018
db First commit Nov 1, 2018
log First commit Nov 1, 2018
public First commit Nov 1, 2018
storage First commit Nov 1, 2018
tmp First commit Nov 1, 2018
.gitignore First commit Nov 1, 2018
.ruby-version First commit Nov 1, 2018
Gemfile First commit Nov 1, 2018
Gemfile.lock First commit Nov 1, 2018 update readme Nov 1, 2018
Rakefile First commit Nov 1, 2018 First commit Nov 1, 2018
package.json First commit Nov 1, 2018

Rails use Active Storage the right way

Rails Active Storage was coming from Rails 5.0, but how can we use it.


The Rails official guides not give we so much details for how can we use it in a real world project.

Some issues:

  1. By default, Active Storage generate URL is for private ACL case.
  2. In image thumb (avatar, cover) cases, it output a long URL, and including sign (by secret_key_base), if we want insert the image URL into a rich text, that unstabe.

So, how can we do?

This project will show you the right way to use Active Storage (:disk service) for the public ACL.

Point change

Add a app/controllers/uploads_controller.rb for instead of Active Storage controller:

class UploadsController < ApplicationController
  before_action :require_disk_service!
  before_action :set_blob

  # GET /upload/:id
  # GET /upload/:id?s=large
  def show
    if params[:s]
      # generate thumb
      variation_key = Blob.variation(params[:s])
      send_file_by_disk_key @blob.representation(variation_key).processed.key, content_type: @blob.content_type
      # return raw file
      send_file_by_disk_key @blob.key, content_type: @blob.content_type, disposition: params[:disposition], filename: @blob.filename


    def send_file_by_disk_key(key, content_type:, disposition: :inline, filename: nil)
      opts = { type: content_type, disposition: disposition, filename: filename }
      send_file Blob.path_for(key), opts

    def set_blob
      @blob = ActiveStorage::Blob.find_by(key: params[:id])
      head :not_found if @blob.blank?

    def require_disk_service!
      head :not_found unless Blob.disk_service?

Do not miss add route:

resources :uploads

We need a app/model/blob.rb to configuation the image resize rules, and provider some method for generate image thumb:

class Blob
  class << self
    IMAGE_SIZES = { tiny: 32, small: 64, medium: 96, xlarge: 2400 }

    def disk_service?
      ActiveStorage::Blob.service.send(:service_name) == "Disk"

    def variation(style) combine_options(style))

    def combine_options(style)
      style = style.to_sym
      size = IMAGE_SIZES[style] || IMAGE_SIZES[:small]

      if style == :xlarge
        { resize: "#{size}>" }
        { thumbnail: "#{size}x#{size}^", gravity: "center", extent: "#{size}x#{size}" }

    def path_for(key)
      ActiveStorage::Blob.service.send(:path_for, key)

Finally, use the upload_path to genrate image URL with the Public URL scenes:

<%= image_tag upload_path(@user.avatar.blob.key, s: :small) %>

You better add a avatar_url method into User model, so use can easily genrate avatar URL for API or serializer.

class User < ApplicationRecord
  def avatar_url(style: :small)
    return "" unless self.avatar.attached?

    Rails.application.routes.url_helpers.upload_path(self.avatar.blob.key, s: style)

More detail please see the files:

  • app/model/blob.rb
  • app/model/user.rb
  • app/model/post.rb
  • config/routes.rb
  • app/controller/uploads_controller.rb
  • app/views/posts/_form.html.erb
  • app/views/posts/show.html.erb
  • app/views/users/_form.html.erb
  • app/views/users/show.html.erb

Getting started

Run migrate

$ git clone
$ cd rails-activestorage-example
$ rails db:create db:migrate
$ rails s

And the visit http://localhost:3000

2018-11-01 5 00 52

2018-11-01 5 00 57

2018-11-01 5 00 39

2018-11-01 5 00 33

You can’t perform that action at this time.