active_storage_db 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +7 -4
- data/app/controllers/active_storage_db/files_controller.rb +22 -16
- data/app/models/active_storage_db/application_record.rb +7 -0
- data/app/models/active_storage_db/file.rb +1 -1
- data/db/migrate/20200702202022_create_active_storage_db_files.rb +15 -2
- data/lib/active_storage/service/db_service.rb +17 -12
- data/lib/active_storage_db/version.rb +1 -1
- data/lib/tasks/active_storage_db_tasks.rake +2 -2
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1a465e1b93b8ab6436f800b2a0ff6e38f049fae621587924d9b2299f3fa06946
|
4
|
+
data.tar.gz: 78583f7c6aa00b0a8c7ab1d98f05d4d34e8ff8a1846f0ed70a0c3e16e97275c7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 76ef220615b3e3704a99803a8bbe3af211855278d3532a97bbc9f325a5455ff393dde657180368d10bdecce8592afe99a41be7f6fe28e325d3671fa3b414087a
|
7
|
+
data.tar.gz: c555f306068194447e708c743abdc829f8043728585da32bbf504d689571d38a72725dbe97382665bd20fdaa95848b48ee018d45ab5d22692c1736ad9bcc59cb
|
data/README.md
CHANGED
@@ -1,16 +1,19 @@
|
|
1
1
|
# Active Storage DB
|
2
2
|
|
3
3
|
[![gem version](https://badge.fury.io/rb/active_storage_db.svg)](https://badge.fury.io/rb/active_storage_db)
|
4
|
+
[![gem downloads](https://badgen.net/rubygems/dt/active_storage_db)](https://rubygems.org/gems/active_storage_db)
|
5
|
+
[![maintainability](https://api.codeclimate.com/v1/badges/92e1e703c308744a0f66/maintainability)](https://codeclimate.com/github/blocknotes/active_storage_db/maintainability)
|
6
|
+
|
4
7
|
[![linters](https://github.com/blocknotes/active_storage_db/actions/workflows/linters.yml/badge.svg)](https://github.com/blocknotes/active_storage_db/actions/workflows/linters.yml)
|
5
|
-
[![specs Postgres](https://github.com/blocknotes/active_storage_db/actions/workflows/
|
6
|
-
[![
|
8
|
+
[![specs Postgres](https://github.com/blocknotes/active_storage_db/actions/workflows/specs_postgres_71.yml/badge.svg)](https://github.com/blocknotes/active_storage_db/actions/workflows/specs_postgres_71.yml)
|
9
|
+
[![specs MySQL](https://github.com/blocknotes/active_storage_db/actions/workflows/specs_mysql_71.yml/badge.svg)](https://github.com/blocknotes/active_storage_db/actions/workflows/specs_mysql_71.yml)
|
7
10
|
|
8
11
|
An Active Storage service upload/download plugin that stores files in a PostgreSQL or MySQL database.
|
9
12
|
|
10
13
|
Main features:
|
11
|
-
-
|
14
|
+
- attachment data stored in a binary field (or blob);
|
12
15
|
- all service methods implemented;
|
13
|
-
-
|
16
|
+
- supports Rails _6_ and _7_.
|
14
17
|
|
15
18
|
Useful also with platforms like Heroku (due to their ephemeral file system).
|
16
19
|
|
@@ -8,34 +8,41 @@ module ActiveStorageDB
|
|
8
8
|
if (key = decode_verified_key)
|
9
9
|
serve_file(key[:key], content_type: key[:content_type], disposition: key[:disposition])
|
10
10
|
else
|
11
|
-
head
|
11
|
+
head(:not_found)
|
12
12
|
end
|
13
13
|
rescue ActiveStorage::FileNotFoundError
|
14
|
-
head
|
14
|
+
head(:not_found)
|
15
15
|
end
|
16
16
|
|
17
17
|
def update
|
18
18
|
if (token = decode_verified_token)
|
19
|
-
|
20
|
-
|
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)
|
24
21
|
else
|
25
|
-
head
|
22
|
+
head(:not_found)
|
26
23
|
end
|
27
24
|
rescue ActiveStorage::IntegrityError
|
28
|
-
head
|
25
|
+
head(:unprocessable_entity)
|
29
26
|
end
|
30
27
|
|
31
28
|
private
|
32
29
|
|
30
|
+
def acceptable_content?(token)
|
31
|
+
token[:content_type] == request.content_mime_type && token[:content_length] == request.content_length
|
32
|
+
end
|
33
|
+
|
33
34
|
def db_service
|
34
35
|
ActiveStorage::Blob.service
|
35
36
|
end
|
36
37
|
|
37
38
|
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
|
39
46
|
end
|
40
47
|
|
41
48
|
def serve_file(key, content_type:, disposition:)
|
@@ -43,15 +50,14 @@ module ActiveStorageDB
|
|
43
50
|
type: content_type || DEFAULT_SEND_FILE_TYPE,
|
44
51
|
disposition: disposition || DEFAULT_SEND_FILE_DISPOSITION
|
45
52
|
}
|
46
|
-
send_data
|
53
|
+
send_data(db_service.download(key), options)
|
47
54
|
end
|
48
55
|
|
49
|
-
def
|
50
|
-
|
51
|
-
end
|
56
|
+
def upload_file(token, body:)
|
57
|
+
return false unless acceptable_content?(token)
|
52
58
|
|
53
|
-
|
54
|
-
|
59
|
+
db_service.upload(token[:key], request.body, checksum: token[:checksum])
|
60
|
+
true
|
55
61
|
end
|
56
62
|
end
|
57
63
|
end
|
@@ -2,12 +2,25 @@
|
|
2
2
|
|
3
3
|
class CreateActiveStorageDBFiles < ActiveRecord::Migration[6.0]
|
4
4
|
def change
|
5
|
-
create_table :active_storage_db_files do |t|
|
5
|
+
create_table :active_storage_db_files, id: primary_key_type do |t|
|
6
6
|
t.string :ref, null: false
|
7
7
|
t.binary :data, null: false
|
8
|
-
|
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
|
9
14
|
|
10
15
|
t.index [:ref], unique: true
|
11
16
|
end
|
12
17
|
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
|
13
26
|
end
|
@@ -36,18 +36,14 @@ module ActiveStorage
|
|
36
36
|
end
|
37
37
|
else
|
38
38
|
instrument :download, key: key do
|
39
|
-
|
40
|
-
raise(ActiveStorage::FileNotFoundError) unless record
|
41
|
-
|
42
|
-
record.data
|
39
|
+
retrieve_file(key)
|
43
40
|
end
|
44
41
|
end
|
45
42
|
end
|
46
43
|
|
47
44
|
def download_chunk(key, range)
|
48
45
|
instrument :download_chunk, key: key, range: range do
|
49
|
-
|
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")
|
51
47
|
raise(ActiveStorage::FileNotFoundError) unless record
|
52
48
|
|
53
49
|
record.chunk
|
@@ -63,7 +59,7 @@ module ActiveStorage
|
|
63
59
|
|
64
60
|
def delete_prefixed(prefix)
|
65
61
|
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
|
67
63
|
end
|
68
64
|
end
|
69
65
|
|
@@ -127,17 +123,26 @@ module ActiveStorage
|
|
127
123
|
end
|
128
124
|
|
129
125
|
def ensure_integrity_of(key, checksum)
|
130
|
-
|
131
|
-
return if Digest::MD5.base64digest(file.data) == checksum
|
126
|
+
return if Digest::MD5.base64digest(object_for(key).data) == checksum
|
132
127
|
|
133
128
|
delete(key)
|
134
129
|
raise ActiveStorage::IntegrityError
|
135
130
|
end
|
136
131
|
|
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
|
+
|
137
144
|
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)
|
141
146
|
(size / @chunk_size.to_f).ceil.times.each do |i|
|
142
147
|
range = (i * @chunk_size..((i + 1) * @chunk_size) - 1)
|
143
148
|
yield download_chunk(key, range)
|
@@ -20,7 +20,7 @@ namespace :asdb do
|
|
20
20
|
desc 'ActiveStorageDB: list attachments ordered by blob id desc'
|
21
21
|
task list: [:environment] do |_t, _args|
|
22
22
|
query = ::ActiveStorage::Blob.order(id: :desc).limit(100)
|
23
|
-
digits =
|
23
|
+
digits = query.ids.inject(0) { |ret, id| size = id.to_s.size; [size, ret].max }
|
24
24
|
|
25
25
|
::ActiveStorage::Tasks.print_blob_header(digits: digits)
|
26
26
|
query.each do |blob|
|
@@ -52,7 +52,7 @@ namespace :asdb do
|
|
52
52
|
|
53
53
|
blobs = ::ActiveStorage::Blob.where('filename LIKE ?', "%#{filename}%").order(id: :desc)
|
54
54
|
if blobs.any?
|
55
|
-
digits =
|
55
|
+
digits = blobs.ids.inject(0) { |ret, id| size = id.to_s.size; [size, ret].max }
|
56
56
|
::ActiveStorage::Tasks.print_blob_header(digits: digits)
|
57
57
|
blobs.each do |blob|
|
58
58
|
::ActiveStorage::Tasks.print_blob(blob, digits: digits)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_storage_db
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mattia Roccoberton
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-10-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activestorage
|
@@ -77,6 +77,7 @@ files:
|
|
77
77
|
- README.md
|
78
78
|
- Rakefile
|
79
79
|
- app/controllers/active_storage_db/files_controller.rb
|
80
|
+
- app/models/active_storage_db/application_record.rb
|
80
81
|
- app/models/active_storage_db/file.rb
|
81
82
|
- config/initializers/inflections.rb
|
82
83
|
- config/routes.rb
|
@@ -104,14 +105,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
104
105
|
requirements:
|
105
106
|
- - ">="
|
106
107
|
- !ruby/object:Gem::Version
|
107
|
-
version: 2.
|
108
|
+
version: 2.7.0
|
108
109
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
109
110
|
requirements:
|
110
111
|
- - ">="
|
111
112
|
- !ruby/object:Gem::Version
|
112
113
|
version: '0'
|
113
114
|
requirements: []
|
114
|
-
rubygems_version: 3.
|
115
|
+
rubygems_version: 3.4.19
|
115
116
|
signing_key:
|
116
117
|
specification_version: 4
|
117
118
|
summary: ActiveStorage DB Service
|