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
Permalink
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
README.md update readme Nov 1, 2018
Rakefile First commit Nov 1, 2018
config.ru First commit Nov 1, 2018
package.json First commit Nov 1, 2018

README.md

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
    else
      # return raw file
      send_file_by_disk_key @blob.key, content_type: @blob.content_type, disposition: params[:disposition], filename: @blob.filename
    end
  end

  private

    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
    end

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

    def require_disk_service!
      head :not_found unless Blob.disk_service?
    end
end

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"
    end

    def variation(style)
      ActiveStorage::Variation.new(combine_options: combine_options(style))
    end

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

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

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

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)
  end
end

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 git@github.com:huacnlee/rails-activestorage-example.git
$ 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.