Skip to content

Commit b37065f

Browse files
author
Mattia Roccoberton
authored
Merge pull request #26 from blocknotes/enhancement/minor-refactorings
Minor internal improvements
2 parents e7f14f2 + eb972e5 commit b37065f

3 files changed

Lines changed: 54 additions & 30 deletions

File tree

app/controllers/active_storage_db/files_controller.rb

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,50 +8,56 @@ def show
88
if (key = decode_verified_key)
99
serve_file(key[:key], content_type: key[:content_type], disposition: key[:disposition])
1010
else
11-
head :not_found
11+
head(:not_found)
1212
end
1313
rescue ActiveStorage::FileNotFoundError
14-
head :not_found
14+
head(:not_found)
1515
end
1616

1717
def update
1818
if (token = decode_verified_token)
19-
if acceptable_content?(token)
20-
db_service.upload(token[:key], request.body, checksum: token[:checksum])
21-
else
22-
head :unprocessable_entity
23-
end
19+
file_uploaded = upload_file(token, body: request.body)
20+
head(file_uploaded ? :no_content : :unprocessable_entity)
2421
else
25-
head :not_found
22+
head(:not_found)
2623
end
2724
rescue ActiveStorage::IntegrityError
28-
head :unprocessable_entity
25+
head(:unprocessable_entity)
2926
end
3027

3128
private
3229

30+
def acceptable_content?(token)
31+
token[:content_type] == request.content_mime_type && token[:content_length] == request.content_length
32+
end
33+
3334
def db_service
3435
ActiveStorage::Blob.service
3536
end
3637

3738
def decode_verified_key
38-
ActiveStorage.verifier.verified(params[:encoded_key], purpose: :blob_key)
39+
key = ActiveStorage.verifier.verified(params[:encoded_key], purpose: :blob_key)
40+
key&.deep_symbolize_keys
41+
end
42+
43+
def decode_verified_token
44+
token = ActiveStorage.verifier.verified(params[:encoded_token], purpose: :blob_token)
45+
token&.deep_symbolize_keys
3946
end
4047

4148
def serve_file(key, content_type:, disposition:)
4249
options = {
4350
type: content_type || DEFAULT_SEND_FILE_TYPE,
4451
disposition: disposition || DEFAULT_SEND_FILE_DISPOSITION
4552
}
46-
send_data db_service.download(key), options
53+
send_data(db_service.download(key), options)
4754
end
4855

49-
def decode_verified_token
50-
ActiveStorage.verifier.verified(params[:encoded_token], purpose: :blob_token)
51-
end
56+
def upload_file(token, body:)
57+
return false unless acceptable_content?(token)
5258

53-
def acceptable_content?(token)
54-
token[:content_type] == request.content_mime_type && token[:content_length] == request.content_length
59+
db_service.upload(token[:key], request.body, checksum: token[:checksum])
60+
true
5561
end
5662
end
5763
end

db/migrate/20200702202022_create_active_storage_db_files.rb

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,25 @@
22

33
class CreateActiveStorageDBFiles < ActiveRecord::Migration[6.0]
44
def change
5-
create_table :active_storage_db_files do |t|
5+
create_table :active_storage_db_files, id: primary_key_type do |t|
66
t.string :ref, null: false
77
t.binary :data, null: false
8-
t.datetime :created_at, null: false
8+
9+
if connection.supports_datetime_with_precision?
10+
t.datetime :created_at, precision: 6, null: false
11+
else
12+
t.datetime :created_at, null: false
13+
end
914

1015
t.index [:ref], unique: true
1116
end
1217
end
18+
19+
private
20+
21+
def primary_key_type
22+
config = Rails.configuration.generators
23+
primary_key_type = config.options[config.orm][:primary_key_type]
24+
primary_key_type || :primary_key
25+
end
1326
end

lib/active_storage/service/db_service.rb

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,18 +36,14 @@ def download(key, &block)
3636
end
3737
else
3838
instrument :download, key: key do
39-
record = ::ActiveStorageDB::File.find_by(ref: key)
40-
raise(ActiveStorage::FileNotFoundError) unless record
41-
42-
record.data
39+
retrieve_file(key)
4340
end
4441
end
4542
end
4643

4744
def download_chunk(key, range)
4845
instrument :download_chunk, key: key, range: range do
49-
chunk_select = "SUBSTRING(data FROM #{range.begin + 1} FOR #{range.size}) AS chunk"
50-
record = ::ActiveStorageDB::File.select(chunk_select).find_by(ref: key)
46+
record = object_for(key, fields: "SUBSTRING(data FROM #{range.begin + 1} FOR #{range.size}) AS chunk")
5147
raise(ActiveStorage::FileNotFoundError) unless record
5248

5349
record.chunk
@@ -63,7 +59,7 @@ def delete(key)
6359

6460
def delete_prefixed(prefix)
6561
instrument :delete_prefixed, prefix: prefix do
66-
::ActiveStorageDB::File.where('ref LIKE ?', "#{prefix}%").destroy_all
62+
::ActiveStorageDB::File.where('ref LIKE ?', "#{ApplicationRecord.sanitize_sql_like(prefix)}%").destroy_all
6763
end
6864
end
6965

@@ -127,17 +123,26 @@ def generate_url(key, expires_in:, filename:, content_type:, disposition:)
127123
end
128124

129125
def ensure_integrity_of(key, checksum)
130-
file = ::ActiveStorageDB::File.find_by(ref: key)
131-
return if Digest::MD5.base64digest(file.data) == checksum
126+
return if Digest::MD5.base64digest(object_for(key).data) == checksum
132127

133128
delete(key)
134129
raise ActiveStorage::IntegrityError
135130
end
136131

132+
def retrieve_file(key)
133+
file = object_for(key)
134+
raise(ActiveStorage::FileNotFoundError) unless file
135+
136+
file.data
137+
end
138+
139+
def object_for(key, fields: nil)
140+
as_file = fields ? ::ActiveStorageDB::File.select(*fields) : ::ActiveStorageDB::File
141+
as_file.find_by(ref: key)
142+
end
143+
137144
def stream(key)
138-
size =
139-
::ActiveStorageDB::File.select('OCTET_LENGTH(data) AS size').find_by(ref: key)&.size ||
140-
raise(ActiveStorage::FileNotFoundError)
145+
size = object_for(key, fields: 'OCTET_LENGTH(data) AS size')&.size || raise(ActiveStorage::FileNotFoundError)
141146
(size / @chunk_size.to_f).ceil.times.each do |i|
142147
range = (i * @chunk_size..((i + 1) * @chunk_size) - 1)
143148
yield download_chunk(key, range)

0 commit comments

Comments
 (0)