класс ActiveStorage::Blob
Blob Active Storage
Blob — это запись, содержащая метаданные файла и ключ, указывающий, где этот файл хранится в сервисе. Blob можно создать двумя способами:
-
До загрузки файла на сервере в сервис с помощью
create_and_upload!. Для этой операции на сервере должен быть доступен перематываемыйioс содержимым файла. -
До прямой загрузки файла с клиента в сервис с помощью
create_before_direct_upload!.
Первый способ не требует интеграции с JavaScript на стороне клиента и может использоваться любым другим серверным сервисом, работающим с файлами. Второй способ быстрее, поскольку для временного хранения загружаемых файлов не используется собственный сервер, и подходит для таких платформ, как Heroku, которые не предоставляют большого объема дискового пространства.
Предполагается, что Blob неизменяемы в отношении ссылки на конкретный файл. При последующих операциях вы можете обновлять метаданные Blob, но не следует обновлять ключ или изменять загруженный файл. Если вам нужно создать производный файл или иначе изменить Blob, просто создайте новый Blob и удалите старый.
Константы
- MINIMUM_TOKEN_LENGTH
Открытые методы класса
# File activestorage/app/models/active_storage/blob.rb, line 144
def compose(blobs, key: nil, filename:, content_type: nil, metadata: nil)
raise ActiveRecord::RecordNotSaved, "All blobs must be persisted." if blobs.any?(&:new_record?)
content_type ||= blobs.pluck(:content_type).compact.first
new(key: key, filename: filename, content_type: content_type, metadata: metadata, byte_size: blobs.sum(&:byte_size)).tap do |combined_blob|
combined_blob.compose(blobs.pluck(:key))
combined_blob.save!
end
end Объединяет несколько Blob в один «составной» Blob.
# File activestorage/app/models/active_storage/blob.rb, line 95
def create_and_upload!(key: nil, io:, filename:, content_type: nil, metadata: nil, service_name: nil, identify: true, record: nil)
create_after_unfurling!(key: key, io: io, filename: filename, content_type: content_type, metadata: metadata, service_name: service_name, identify: identify).tap do |blob|
blob.upload_without_unfurling(io)
end
end Создает новый экземпляр Blob, а затем загружает содержимое указанного io в сервис. Экземпляр Blob сохраняется до начала загрузки, чтобы из-за совпадения ключей загрузка не перезаписала другой файл. Чтобы указать тип содержимого, передайте identify: false и отключите автоматическое определение типа содержимого.
# File activestorage/app/models/active_storage/blob.rb, line 106 def create_before_direct_upload!(key: nil, filename:, byte_size:, checksum:, content_type: nil, metadata: nil, service_name: nil, record: nil) create! key: key, filename: filename, byte_size: byte_size, checksum: checksum, content_type: content_type, metadata: metadata, service_name: service_name end
Возвращает сохраненный Blob без загрузки файла в сервис. Этот Blob указывает на ключ, для которого пока не существует файла. Такой способ предназначен для использования совместно с загрузкой на стороне клиента: сначала создается Blob, чтобы сформировать подписанный URL для загрузки. Этот URL указывает на ключ, созданный для Blob. После отправки формы, использующей прямую загрузку, Blob можно связать с нужной записью с помощью подписанного идентификатора.
# File activestorage/app/models/active_storage/blob.rb, line 69 def find_signed(id, record: nil, purpose: :blob_id) super(id, purpose: purpose) end
Подписанный идентификатор Blob можно использовать для ссылки на него на стороне клиента, не опасаясь подделки. Это особенно полезно при прямой загрузке, когда клиенту нужно сослаться на Blob, созданный до самой загрузки при отправке формы.
Подписанный идентификатор также используется для создания стабильных URL-адресов Blob через BlobsController.
# File activestorage/app/models/active_storage/blob.rb, line 76 def find_signed!(id, record: nil, purpose: :blob_id) super(id, purpose: purpose) end
Работает как find_signed, но вызывает исключение ActiveSupport::MessageVerifier::InvalidSignature, если срок действия signed_id истек, его назначение не совпадает или он был подделан. Также вызывает исключение ActiveRecord::RecordNotFound, если по корректному подписанному идентификатору не удалось найти запись.
# File activestorage/app/models/active_storage/blob.rb, line 115 def generate_unique_secure_token(length: MINIMUM_TOKEN_LENGTH) SecureRandom.base36(length) end
Чтобы избежать проблем с файловыми системами, не различающими регистр, особенно при работе с базами данных, в которых индексы считаются чувствительными к регистру, все сгенерированные ключи Blob содержат только символы алфавита base-36 и поэтому записываются строчными буквами. Чтобы обеспечить такую же или более высокую энтропию, как в кодировке base-58, используемой в has_secure_token, количество используемых байтов увеличено с обычных 24 до 28.
# File activestorage/app/models/active_storage/blob.rb, line 38
scope :unattached, -> { where.missing(:attachments) }
Возвращает Blob, не связанные ни с одной записью.
Открытые методы экземпляра
# File activestorage/app/models/active_storage/blob.rb, line 32 has_many :attachments, autosave: false
Возвращает связанные экземпляры ActiveStorage::Attachment.
# File activestorage/app/models/active_storage/blob.rb, line 196
def audio?
content_type.start_with?("audio")
end Возвращает true, если content_type этого Blob относится к аудиоформатам, например audio/mpeg.
# File activestorage/app/models/active_storage/blob.rb, line 182
def custom_metadata
self[:metadata][:custom] || {}
end # File activestorage/app/models/active_storage/blob.rb, line 186 def custom_metadata=(metadata) self[:metadata] = self[:metadata].merge(custom: metadata) end
# File activestorage/app/models/active_storage/blob.rb, line 306
def delete
service.delete(key)
service.delete_prefixed("variants/#{key}/") if image?
end Удаляет файлы, связанные с Blob, из сервиса. Это следует делать только в том случае, если сам Blob тоже будет удален, иначе останется неработающая ссылка. В большинстве случаев рекомендуется использовать методы purge и purge_later.
# File activestorage/app/models/active_storage/blob.rb, line 266 def download(&block) service.download key, &block end
Загружает файл, связанный с этим Blob. Если блок не передан, весь файл считывается в память и возвращается. Для очень больших файлов это потребует много оперативной памяти. Если блок передан, загрузка выполняется потоком, а данные передаются блоками.
# File activestorage/app/models/active_storage/blob.rb, line 271 def download_chunk(range) service.download_chunk key, range end
Загружает часть файла, связанного с этим Blob.
# File activestorage/app/models/active_storage/blob.rb, line 178 def filename ActiveStorage::Filename.new(self[:filename]) end
Возвращает экземпляр ActiveStorage::Filename для имени файла, у которого можно получить базовое имя, расширение и безопасный для использования в URL-адресах вариант имени.
# File activestorage/app/models/active_storage/blob.rb, line 191
def image?
content_type.start_with?("image")
end Возвращает true, если content_type этого Blob относится к форматам изображений, например image/png.
# File activestorage/app/models/active_storage/blob.rb, line 170 def key # We can't wait until the record is first saved to have a key for it self[:key] ||= self.class.generate_unique_secure_token(length: MINIMUM_TOKEN_LENGTH) end
Возвращает ключ, указывающий на файл, связанный с этим Blob в сервисе. Ключ имеет формат защищенного токена Rails и состоит из строчных букв. Например: xtapjjcjiudrlk3tmwyjgpuobabd. Этот ключ не предназначен для непосредственного показа пользователю. Всегда обращайтесь к Blob с помощью signed_id или проверенного варианта ключа.
# File activestorage/app/models/active_storage/blob.rb, line 288
def open(tmpdir: nil, &block)
service.open(
key,
checksum: checksum,
verify: !composed,
name: [ "ActiveStorage-#{id}-", filename.extension_with_delimiter ],
tmpdir: tmpdir,
&block
)
end Загружает Blob во временный файл на диске и передает этот файл блоку.
Имя временного файла начинается с ActiveStorage- и идентификатора Blob. Расширение файла совпадает с расширением Blob.
По умолчанию временный файл создается в Dir.tmpdir. Передайте tmpdir:, чтобы создать его в другом каталоге:
blob.open(tmpdir: "/path/to/tmp") do |file| # ... end
После выполнения переданного блока временный файл автоматически закрывается и удаляется.
Вызывает исключение ActiveStorage::IntegrityError, если контрольная сумма загруженных данных не совпадает с контрольной суммой Blob.
# File activestorage/app/models/active_storage/blob.rb, line 314 def purge destroy delete if previously_persisted? rescue ActiveRecord::InvalidForeignKey end
Удаляет запись Blob, а затем удаляет файл из сервиса. Это рекомендуемый способ избавления от ненужных Blob. Однако удаление файла из сервиса устанавливает HTTP-соединение с сервисом, которое может быть медленным или невозможным, поэтому этот метод не следует использовать внутри транзакции или в обратных вызовах. Вместо него используйте purge_later.
# File activestorage/app/models/active_storage/blob.rb, line 322 def purge_later ActiveStorage::PurgeJob.perform_later(self) end
Добавляет в очередь ActiveStorage::PurgeJob для вызова purge. Это рекомендуемый способ удаления Blob из транзакции, обратного вызова Active Record или в любом другом сценарии, требующем немедленной обработки.
# File activestorage/app/models/active_storage/blob.rb, line 327 def service services.fetch(service_name) end
Возвращает экземпляр сервиса, который можно настроить глобально или для отдельного вложения.
# File activestorage/app/models/active_storage/blob.rb, line 226 def service_headers_for_direct_upload service.headers_for_direct_upload key, filename: filename, content_type: content_type, content_length: byte_size, checksum: checksum, custom_metadata: custom_metadata end
Возвращает Hash заголовков для запросов service_url_for_direct_upload.
# File activestorage/app/models/active_storage/blob.rb, line 221 def service_url_for_direct_upload(expires_in: ActiveStorage.service_urls_expire_in) service.url_for_direct_upload key, expires_in: expires_in, content_type: content_type, content_length: byte_size, checksum: checksum, custom_metadata: custom_metadata end
Возвращает URL-адрес, который можно использовать для прямой загрузки файла этого Blob в сервис. В целях безопасности срок действия этого URL-адреса должен быть небольшим; он создается по запросу JavaScript-кодом на стороне клиента, отвечающим за загрузку.
# File activestorage/app/models/active_storage/blob.rb, line 162 def signed_id(purpose: :blob_id, expires_in: nil, expires_at: nil) super end
Возвращает подписанный идентификатор этого Blob, который можно безопасно использовать для ссылок на него на стороне клиента.
# File activestorage/app/models/active_storage/blob.rb, line 206
def text?
content_type.start_with?("text")
end Возвращает true, если content_type этого Blob относится к текстовым форматам, например text/plain.
# File activestorage/app/models/active_storage/blob.rb, line 243 def upload(io, identify: true) unfurl io, identify: identify upload_without_unfurling io end
Загружает io в сервис по key для этого Blob. Предполагается, что Blob неизменяемы, поэтому не следует использовать этот метод после того, как файл уже загружен для Blob. Если вы хотите создать производный Blob, вместо этого просто создайте новый Blob на основе старого.
Перед загрузкой мы вычисляем контрольную сумму, которая отправляется в сервис для проверки целостности при передаче. Если контрольная сумма полученных сервисом данных не совпадет, будет вызвано исключение. Мы также измеряем размер io и сохраняем его в byte_size записи Blob. Тип содержимого автоматически извлекается из io, если вы не укажете content_type и не передадите false в identify.
Как правило, вам вообще не нужно вызывать этот метод напрямую. Вместо этого используйте метод класса create_and_upload!. Если вы все же вызываете этот метод напрямую, убедитесь, что используете его для сохраненного Blob, иначе данные другого Blob могут быть перезаписаны в сервисе.
# File activestorage/app/models/active_storage/blob.rb, line 214
def url(expires_in: ActiveStorage.service_urls_expire_in, disposition: :inline, filename: nil, **options)
service.url key, expires_in: expires_in, filename: ActiveStorage::Filename.wrap(filename || self.filename),
content_type: content_type_for_serving, disposition: forced_disposition_for_serving || disposition, **options
end Возвращает URL-адрес Blob в сервисе. Для общедоступных файлов возвращается постоянный URL-адрес, а для закрытых — URL-адрес с коротким сроком действия. URL-адреса закрытых файлов подписаны и не предназначены для общего использования. Их следует предоставлять только в виде перенаправления со стабильного, при необходимости защищенного авторизацией URL-адреса. Скрытие URL-адреса за перенаправлением также позволяет сменить сервис, не обновляя все URL-адреса.
# File activestorage/app/models/active_storage/blob.rb, line 201
def video?
content_type.start_with?("video")
end Возвращает true, если content_type этого Blob относится к видеоформатам, например video/mp4.
© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.