модуль ActiveStorage
Active Storage
Active Storage упрощает загрузку файлов в облачные сервисы, такие как Amazon S3 или Google Cloud Storage, и прикрепление этих файлов к записям Active Record. Поддерживается использование одного основного сервиса и его зеркал в других сервисах для обеспечения избыточности. Также предоставляется дисковый сервис для тестирования или локального развёртывания, однако основное внимание уделено облачному хранилищу.
Файлы можно загружать с сервера в облако или напрямую с клиента в облако.
Кроме того, файлы изображений можно преобразовывать с помощью вариантов, создаваемых по запросу, изменяя качество, соотношение сторон, размер или выполняя любые другие преобразования, поддерживаемые MiniMagick или Vips.
Подробнее об Active Storage можно прочитать в руководстве Обзор Active Storage.
Сравнение с другими решениями для хранения
Ключевое отличие Active Storage от других решений для вложений в Rails заключается в использовании встроенных моделей Blob и Attachment (на основе Active Record). Это означает, что существующие модели приложения не нужно изменять, добавляя дополнительные столбцы для связи с файлами. Active Storage использует полиморфные ассоциации через промежуточную модель Attachment, которая связывается с самим объектом Blob.
Модели Blob хранят метаданные вложения (имя файла, тип содержимого и т. д.) и ключ-идентификатор в службе хранения. Модели Blob не хранят сами двоичные данные. По своей сути они предназначены быть неизменяемыми. Один файл — один blob. Также можно связать один и тот же blob с несколькими моделями приложения. Если вы хотите преобразовать заданный Blob, предполагается, что вы просто создадите новый, а не будете пытаться изменить существующий (хотя, конечно, позже можно удалить предыдущую версию, если она больше не нужна).
Установка
Выполните bin/rails active_storage:install, чтобы скопировать миграции active_storage.
ПРИМЕЧАНИЕ: если задачу не удаётся найти, убедитесь, что require "active_storage/engine" присутствует в config/application.rb.
Примеры
Одно вложение:
class User < ApplicationRecord
# Associates an attachment and a blob. When the user is destroyed they are
# purged by default (models destroyed, and resource files deleted).
has_one_attached :avatar
end
# Attach an avatar to the user.
user.avatar.attach(io: File.open("/path/to/face.jpg"), filename: "face.jpg", content_type: "image/jpeg")
# Does the user have an avatar?
user.avatar.attached? # => true
# Synchronously destroy the avatar and actual resource files.
user.avatar.purge
# Destroy the associated models and actual resource files async, via Active Job.
user.avatar.purge_later
# Does the user have an avatar?
user.avatar.attached? # => false
# Generate a permanent URL for the blob that points to the application.
# Upon access, a redirect to the actual service endpoint is returned.
# This indirection decouples the public URL from the actual one, and
# allows for example mirroring attachments in different services for
# high-availability. The redirection has an HTTP expiration of 5 min.
url_for(user.avatar)
class AvatarsController < ApplicationController
def update
# params[:avatar] contains an ActionDispatch::Http::UploadedFile object
Current.user.avatar.attach(params.require(:avatar))
redirect_to Current.user
end
end
Несколько вложений:
class Message < ApplicationRecord has_many_attached :images end
<%= form_with model: @message, local: true do |form| %> <%= form.text_field :title, placeholder: "Title" %><br> <%= form.textarea :content %><br><br> <%= form.file_field :images, multiple: true %><br> <%= form.submit %> <% end %>
class MessagesController < ApplicationController
def index
# Use the built-in with_attached_images scope to avoid N+1
@messages = Message.all.with_attached_images
end
def create
message = Message.create! params.expect(message: [ :title, :content, images: [] ])
redirect_to message
end
def show
@message = Message.find(params[:id])
end
end
Variation вложения изображения:
<%# Hitting the variant URL will lazy transform the original blob and then redirect to its new service location %> <%= image_tag user.avatar.variant(resize_to_limit: [100, 100]) %>
File стратегии раздачи файлов
Active Storage поддерживает два способа раздачи файлов: перенаправление и проксирование.
Перенаправление
Active Storage генерирует постоянные URL-адреса приложения для файлов, при обращении к которым выполняется перенаправление на подписанные URL-адреса службы с коротким сроком действия. Это освобождает серверы приложения от необходимости раздавать данные файлов. Это стратегия раздачи файлов по умолчанию.
Если приложение по умолчанию настроено на проксирование файлов, используйте помощники маршрутов rails_storage_redirect_path и _url для перенаправления:
<%= image_tag rails_storage_redirect_path(@user.avatar) %>
Проксирование
Вместо этого файлы можно проксировать. Это означает, что серверы приложения будут загружать данные файлов из службы хранения в ответ на запросы. Это может быть полезно для раздачи файлов через CDN.
Можно настроить Active Storage на использование проксирования по умолчанию:
# config/initializers/active_storage.rb Rails.application.config.active_storage.resolve_model_to_route = :rails_storage_proxy
Если же вы хотите явно проксировать определённые вложения, можно использовать помощники URL в форме rails_storage_proxy_path и rails_storage_proxy_url.
<%= image_tag rails_storage_proxy_path(@user.avatar) %>
Прямая загрузка
Active Storage вместе со встроенной библиотекой JavaScript поддерживает загрузку файлов напрямую с клиента в облако.
Установка прямой загрузки
-
Подключите JavaScript Active Storage к пакету JavaScript приложения или добавьте прямую ссылку на него.
Прямое подключение без сборки через конвейер ресурсов в HTML приложения с автозапуском:
<%= javascript_include_tag "activestorage" %>
Подключение через importmap-rails без сборки через конвейер ресурсов в HTML приложения без автозапуска в формате ESM:
# config/importmap.rb pin "@rails/activestorage", to: "activestorage.esm.js"
<script type="module-shim"> import * as ActiveStorage from "@rails/activestorage" ActiveStorage.start() </script>
Использование конвейера ресурсов:
//= require activestorage
Использование пакета npm:
import * as ActiveStorage from "@rails/activestorage" ActiveStorage.start()
-
Добавьте к полям ввода файлов атрибут с URL-адресом прямой загрузки.
<%= form.file_field :attachments, multiple: true, direct_upload: true %>
-
Настройте CORS в сторонних службах хранения, чтобы разрешить запросы прямой загрузки.
-
Готово! Загрузка начинается при отправке формы.
События JavaScript прямой загрузки
| Имя события | Цель события | Данные события (event.detail) | Описание |
|---|---|---|---|
direct-uploads:start | <form> | Нет | Отправлена форма, содержащая поля прямой загрузки файлов. |
direct-upload:initialize | <input> | {id, file} | Вызывается для каждого файла после отправки формы. |
direct-upload:start | <input> | {id, file} | Начинается прямая загрузка. |
direct-upload:before-blob-request | <input> | {id, file, xhr} | Перед отправкой запроса приложению для получения метаданных прямой загрузки. |
direct-upload:before-storage-request | <input> | {id, file, xhr} | Перед отправкой запроса на сохранение файла. |
direct-upload:progress | <input> | {id, file, progress} | По мере выполнения запросов на сохранение файлов. |
direct-upload:error | <input> | {id, file, error} | Произошла ошибка. Если это событие не отменено, будет показано alert. |
direct-upload:end | <input> | {id, file} | Прямая загрузка завершена. |
direct-uploads:end | <form> | Нет | Все прямые загрузки завершены. |
Лицензия
Active Storage распространяется на условиях лицензии MIT.
Поддержка
Документация API находится по адресу:
Сообщения об ошибках в проекте Ruby on Rails можно отправлять сюда:
Запросы на добавление функций следует обсуждать на форуме rubyonrails-core здесь:
Открытые методы класса
# File activestorage/lib/active_storage/gem_version.rb, line 5 def self.gem_version Gem::Version.new VERSION::STRING end
Возвращает текущую загруженную версию Active Storage в виде Gem::Version.
# File activestorage/lib/active_storage/version.rb, line 7 def self.version gem_version end
Возвращает текущую загруженную версию Active Storage в виде Gem::Version.
© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.