11# frozen_string_literal: true
22
33module ActiveStorage
4+ # Wraps a DB table as an Active Storage service. See ActiveStorage::Service
5+ # for the generic API documentation that applies to all services.
46 class Service ::DBService < Service
57 def initialize ( **)
68 @chunk_size = ENV . fetch ( 'ASDB_CHUNK_SIZE' ) { 1 . megabytes }
@@ -22,22 +24,27 @@ def download(key, &block)
2224 else
2325 instrument :download , key : key do
2426 record = ::ActiveStorageDB ::File . find_by ( ref : key )
25- record &.data || raise ( ActiveStorage ::FileNotFoundError )
27+ raise ( ActiveStorage ::FileNotFoundError ) unless record
28+
29+ record . data
2630 end
2731 end
2832 end
2933
3034 def download_chunk ( key , range )
3135 instrument :download_chunk , key : key , range : range do
3236 chunk_select = "SUBSTRING(data FROM #{ range . begin + 1 } FOR #{ range . size } ) AS chunk"
33- ::ActiveStorageDB ::File . select ( chunk_select ) . find_by ( ref : key ) &.chunk ||
34- raise ( ActiveStorage ::FileNotFoundError )
37+ record = ::ActiveStorageDB ::File . select ( chunk_select ) . find_by ( ref : key )
38+ raise ( ActiveStorage ::FileNotFoundError ) unless record
39+
40+ record . chunk
3541 end
3642 end
3743
3844 def delete ( key )
3945 instrument :delete , key : key do
4046 ::ActiveStorageDB ::File . find_by ( ref : key ) &.destroy
47+ # Ignore files already deleted
4148 end
4249 end
4350
@@ -55,31 +62,14 @@ def exist?(key)
5562 end
5663 end
5764
58- def url ( key , expires_in :, filename :, disposition :, content_type :)
59- instrument :url , key : key do |payload |
60- content_disposition = content_disposition_with ( type : disposition , filename : filename )
61- verified_key_with_expiration = ActiveStorage . verifier . generate (
62- {
63- key : key ,
64- disposition : content_disposition ,
65- content_type : content_type
66- } ,
67- expires_in : expires_in ,
68- purpose : :blob_key
69- )
70- current_uri = URI . parse ( current_host )
71- generated_url = url_helpers . service_url (
72- verified_key_with_expiration ,
73- protocol : current_uri . scheme ,
74- host : current_uri . host ,
75- port : current_uri . port ,
76- disposition : content_disposition ,
77- content_type : content_type ,
78- filename : filename
79- )
80- payload [ :url ] = generated_url
81-
82- generated_url
65+ if Rails ::VERSION ::MAJOR == 6 && Rails ::VERSION ::MINOR == 0
66+ def url ( key , expires_in :, filename :, disposition :, content_type :)
67+ instrument :url , key : key do |payload |
68+ opts = { expires_in : expires_in , filename : filename , content_type : content_type , disposition : disposition }
69+ generate_url ( key , opts ) . tap do |generated_url |
70+ payload [ :url ] = generated_url
71+ end
72+ end
8373 end
8474 end
8575
@@ -90,15 +80,16 @@ def url_for_direct_upload(key, expires_in:, content_type:, content_length:, chec
9080 key : key ,
9181 content_type : content_type ,
9282 content_length : content_length ,
93- checksum : checksum
83+ checksum : checksum ,
84+ service_name : respond_to? ( :name ) ? name : 'db'
9485 } ,
9586 expires_in : expires_in ,
9687 purpose : :blob_token
9788 )
98- generated_url = url_helpers . update_service_url ( verified_token_with_expiration , host : current_host )
99- payload [ :url ] = generated_url
10089
101- generated_url
90+ url_helpers . update_service_url ( verified_token_with_expiration , url_options ) . tap do |generated_url |
91+ payload [ :url ] = generated_url
92+ end
10293 end
10394 end
10495
@@ -119,6 +110,39 @@ def current_host
119110 end
120111 end
121112
113+ def private_url ( key , expires_in :, filename :, content_type :, disposition :, **)
114+ generate_url ( key , expires_in : expires_in , filename : filename , content_type : content_type , disposition : disposition )
115+ end
116+
117+ def public_url ( key , filename :, content_type : nil , disposition : :attachment , **)
118+ generate_url ( key , expires_in : nil , filename : filename , content_type : content_type , disposition : disposition )
119+ end
120+
121+ def generate_url ( key , expires_in :, filename :, content_type :, disposition :)
122+ content_disposition = content_disposition_with ( type : disposition , filename : filename )
123+ verified_key_with_expiration = ActiveStorage . verifier . generate (
124+ {
125+ key : key ,
126+ disposition : content_disposition ,
127+ content_type : content_type ,
128+ service_name : respond_to? ( :name ) ? name : 'db'
129+ } ,
130+ expires_in : expires_in ,
131+ purpose : :blob_key
132+ )
133+
134+ current_uri = URI . parse ( current_host )
135+ url_helpers . service_url (
136+ verified_key_with_expiration ,
137+ protocol : current_uri . scheme ,
138+ host : current_uri . host ,
139+ port : current_uri . port ,
140+ disposition : content_disposition ,
141+ content_type : content_type ,
142+ filename : filename
143+ )
144+ end
145+
122146 def ensure_integrity_of ( key , checksum )
123147 file = ::ActiveStorageDB ::File . find_by ( ref : key )
124148 return if Digest ::MD5 . base64digest ( file . data ) == checksum
@@ -140,5 +164,13 @@ def stream(key)
140164 def url_helpers
141165 @url_helpers ||= ::ActiveStorageDB ::Engine . routes . url_helpers
142166 end
167+
168+ def url_options
169+ if ActiveStorage ::Current . respond_to? :url_options
170+ ActiveStorage ::Current . url_options
171+ else
172+ { host : ActiveStorage ::Current . host }
173+ end
174+ end
143175 end
144176end
0 commit comments