Active Storage Blob
Blob 是記錄,其中包含關於檔案的附屬資料和該檔案在服務上位置的鍵值。Blob 可透過以下兩種方式建立
-
在檔案經由伺服器端上傳至服務之前,使用
create_and_upload!
。此作業必須在伺服器上使用可回溯的io
和檔案內容。 -
在檔案直接上傳至服務的客戶端之前,使用
create_before_direct_upload!
。
第一個選項不需要任何客戶端 JavaScript 整合,並且可以由處理檔案的任何其它後端服務使用。第二個選項較快,因為您不用把自己的伺服器當成上傳的暫存點,並且可以與不提供大量磁碟空間的部署(例如 Heroku)搭配使用。
Blob 旨於對專門檔案參考保持不變。允許您在後續的傳遞中更新 blob 的附屬資料,但您不應該更新鍵值或變更上傳的檔案。如果您需要建構衍生品,或是變更 blob,只需建構新的 blob,並移除舊的 blob。
- 模組 ActiveStorage::Blob::Analyzable
- 模組 ActiveStorage::Blob::Identifiable
- 模組 ActiveStorage::Blob::Representable
- A
- C
- D
- F
- G
- I
- K
- O
- P
- S
- T
- U
- V
- ActiveStorage::Blob::Analyzable
- ActiveStorage::Blob::Identifiable
- ActiveStorage::Blob::Representable
常數
MINIMUM_TOKEN_LENGTH | = | 28 |
類別共用方法
compose(blobs, key: nil, filename:, content_type: nil, metadata: nil) 連結
將多個 blob 合併成單一的「已組合」blob。
來源: 顯示 | 在 GitHub 上
# 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
create_and_upload!(key: nil, io:, filename:, content_type: nil, metadata: nil, service_name: nil, identify: true, record: nil) 連結
建立新的 blob 實例,然後上傳給定 io
的內容到服務。blob 實例會在開始上傳之前儲存,以防止上傳因為金鑰衝突而覆寫掉其他 blob。當提供內容類型時,傳遞 identify: false
以略過自動內容類型推論。
來源:顯示 | 在 GitHub 上
# 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
create_before_direct_upload!(key: nil, filename:, byte_size:, checksum:, content_type: nil, metadata: nil, service_name: nil, record: nil) 連結
傳回已儲存的 blob,而不將檔案上傳到服務。此 blob 將指向尚未有檔案的金鑰。預期搭配客戶端上傳一起使用,這會先建立 blob 以產生用於上傳的簽署網址。此簽署網址指向blob產生的金鑰。一旦提交使用直接上傳的表單,就可以使用簽署 ID 將blob關聯到正確的記錄。
來源:顯示 | 在 GitHub 上
# 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
find_signed(id, record: nil, purpose: :blob_id) 連結
可以使用 blob 的簽署 ID 在客戶端端參考它,而不用擔心被竄改。對於直接上傳特別有幫助,其中客户端需要在表單提交時參考上傳之前建立的 blob。
簽署 ID 還有透過 BlobsController 為 blob 建立穩定網址。
來源:顯示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 69 def find_signed(id, record: nil, purpose: :blob_id) super(id, purpose: purpose) end
find_signed!(id, record: nil, purpose: :blob_id) 連結
運作方式與 `find_signed` 相同,但是如果 `signed_id` 已過期、目的不符或已被竄改,會引發 `ActiveSupport::MessageVerifier::InvalidSignature` 例外。如果有效簽署 ID 無法找到記錄,它還會引發 `ActiveRecord::RecordNotFound` 例外。
來源:顯示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 76 def find_signed!(id, record: nil, purpose: :blob_id) super(id, purpose: purpose) end
generate_unique_secure_token(length: MINIMUM_TOKEN_LENGTH) 連結
為了防止大小寫不敏感的檔案系統出問題,特別是搭配將索引視為大小寫敏感的資料庫時,所有產生的 blob 金鑰只會包含 base-36 字元,因此會是全部小寫。為維持與 `has_secure_token` 使用的 base-58 編碼相同或更高的熵值,所使用的位元組數從標準的 24 個增加到 28 個
資料來源:顯示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 115 def generate_unique_secure_token(length: MINIMUM_TOKEN_LENGTH) SecureRandom.base36(length) end
未附檔 連結
傳回未附檔到任一記錄的 blob。
資料來源:顯示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 38 scope :unattached, -> { where.missing(:attachments) }
執行個體公用方法
附檔 連結
傳回關聯的 ActiveStorage::Attachment
個體。
資料來源:顯示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 32 has_many :attachments
音訊?() 連結
如果這個 blob 的內容類型屬於音訊範圍,例如 audio/mpeg,則傳回 true。
資料來源:顯示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 212 def audio? content_type.start_with?("audio") end
自訂元資料() 連結
資料來源:顯示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 198 def custom_metadata self[:metadata][:custom] || {} end
自訂元資料=(metadata) 連結
資料來源:顯示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 202 def custom_metadata=(metadata) self[:metadata] = self[:metadata].merge(custom: metadata) end
刪除() 連結
刪除與 blob 關聯的服務上的檔案。這只應在 blob 準備要刪除,否則你將會擁有實際上已死的參考。建議在多數情況下,使用 purge
和 purge_later
方法。
資料來源:顯示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 322 def delete service.delete(key) service.delete_prefixed("variants/#{key}/") if image? end
下載(&block) 連結
下載與這個 blob 關聯的檔案。如果沒有給出區塊,則會將整個檔案讀取到記憶體中並傳回。對於超大型檔案,這樣會使用大量的 RAM。如果給出區塊,則會串流下載並以區塊為單位讓出。
資料來源:顯示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 282 def download(&block) service.download key, &block end
下載區塊(range) 連結
下載與這個 blob 關聯的檔案的部分內容。
資料來源:顯示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 287 def download_chunk(range) service.download_chunk key, range end
檔案名稱() 連結
傳回檔案名稱的 ActiveStorage::Filename
實例,可查詢基本檔名、副檔名和安全版本(可安全使用於 URL)的檔名。
來源: 顯示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 194 def filename ActiveStorage::Filename.new(self[:filename]) end
image?() 連結
如果這項 blob 的 content_type 屬於影像範圍(例如 image/png),則傳回 true。
來源: 顯示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 207 def image? content_type.start_with?("image") end
key() 連結
傳回指向與此 blob 關聯的服務上的檔案的 key。此 key 是小寫的 Rails 安全令牌格式。因此看起來像:xtapjjcjiudrlk3tmwyjgpuobabd。這項 key 並非預計直接顯示給使用者。請務必使用 signed_id
或驗證過的 key 形式來參考 blob。
來源: 顯示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 186 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
open(tmpdir: nil, &block) 連結
下載 blob 到磁碟上的暫存檔案。傳回暫存檔案。
暫存檔案的名稱加上 ActiveStorage-
前綴和 blob 的 ID。其副檔名與 blob 的副檔名相符。
預設在 Dir.tmpdir
中建立暫存檔案。傳遞 tmpdir:
在不同的目錄中建立
blob.open(tmpdir: "/path/to/tmp") do |file|
# ...
end
執行所提供的區塊後,暫存檔案會自動關閉和解除連結。
如果下載的資料與 blob 的檢查碼不符,會引发 ActiveStorage::IntegrityError
。
來源: 顯示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 304 def open(tmpdir: nil, &block) service.open( key, checksum: checksum, verify: !composed, name: [ "ActiveStorage-#{id}-", filename.extension_with_delimiter ], tmpdir: tmpdir, &block ) end
purge() 連結
清除 blob 記錄,然後刪除服務中的檔案。這是處理不需要的 blob 的建議方法。但請注意,從服務中刪除檔案會初始化與服務的 HTTP 連線,可能會很慢或無法進行,因此您不可以在交易或 CallBack 中使用此方法。請改用 purge_later
。
來源: 顯示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 330 def purge destroy delete if previously_persisted? rescue ActiveRecord::InvalidForeignKey end
purge_later() 連結
排定 ActiveStorage::PurgeJob
來呼叫 purge
。這是從交易、ActiveRecord CallBack 或任何其他即時場景中清除 blob 的建議方法。
來源: 顯示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 338 def purge_later ActiveStorage::PurgeJob.perform_later(self) end
service() 連結
傳回服務的實例,可以針對全局或每個附加元件設定
來源: 顯示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 343 def service services.fetch(service_name) end
service_headers_for_direct_upload() 連結
傳回一個 Hash
,其中包含 `service_url_for_direct_upload` 要求的標頭。
來源:show | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 242 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
service_url_for_direct_upload(expires_in: ActiveStorage.service_urls_expire_in) 連結
傳回此服務上可直接上傳 blob 檔案的 URL。此 URL 僅供暫時使用以維持安全性,且只會在負責上傳的用戶端 JavaScript 請求時才產生。
來源:show | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 237 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
signed_id(purpose: :blob_id, expires_in: nil, expires_at: nil) 連結
傳回此 blob 的簽署 ID,此 ID 適用於用戶端,無需擔心遭到入侵。
來源:show | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 178 def signed_id(purpose: :blob_id, expires_in: nil, expires_at: nil) super end
text?() 連結
如果此 blob 的 content_type 屬於文字類別(例如文字/普通),則傳回 true。
來源:show | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 222 def text? content_type.start_with?("text") end
upload(io, identify: true) 連結
將 io
上傳至此 blob 的 key
上的服務。Blob 應為不可變動,因此在檔案已上傳至符合 blob 後,請勿使用此方法。如果您想要建立派生 blob,您應該直接根據舊 blob 建立新的 blob。
上傳前,我們會計算雜湊,並將其傳送至服務以進行傳輸完整性驗證。如果雜湊與服務接收到的資料不符,則會引發例外狀況。我們也會測量 io
的大小,並將其儲存在 blob 記錄的 byte_size
中。內容類型會自動從 io
中提取,除非您指定一個 content_type
並將 identify
傳遞為 false。
正常情況下,您根本不必直接呼叫此方法。請改用 create_and_upload!
類別方法。如果您直接使用此方法,請確定您在持久的 Blob
上使用它,否則可能會覆寫服務上其他 blob 的資料。
來源:show | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 259 def upload(io, identify: true) unfurl io, identify: identify upload_without_unfurling io end
url(expires_in: ActiveStorage.service_urls_expire_in, disposition: :inline, filename: nil, **options) 連結
傳回服務上 blob 的 URL。對於公開的檔案,此處會傳回永久 URL,而對於私有的檔案,此處會傳回暫時 URL。私人檔案是簽署的,不可公開使用。相反的,URL 應該只以重定向的方式,從穩定且可能已驗證的 URL 顯示。將 URL 隱藏在重定向後面,還能讓您在不更新所有 URL 的情況下變更服務。
來源:show | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 230 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
video?() 連結
如果此 blob 的 content_type 位於視訊範圍中,如 video/mp4,則傳回 true。
資料來源: 顯示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 217 def video? content_type.start_with?("video") end