active_storage-postgresql 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +5 -2
- data/lib/active_storage/postgresql/file.rb +42 -13
- data/lib/active_storage/postgresql/version.rb +1 -1
- data/lib/active_storage/service/postgresql_service.rb +17 -35
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8e03540828022cafb6f37bcb926ed367951072e40af4970f51809b796e5fc8d5
|
4
|
+
data.tar.gz: 369c7335dfbb46aa1add165303bbb8c505600df7be8dc08663968b35884a08d5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ffc0882ec92da092e0954498f3815367b9d52b6329e4aae764531cb888ffdd22b87ebaffd8189acb3c2750db71af0badf632642c57b3fd5ff30d80dc22100042
|
7
|
+
data.tar.gz: 9e4aabe7a6cd2dbf777749078db3e2d382ff385067bdd045883d5a3b56cab9bbc5dbe3926f191451c394677b2d4e76f7e00c315c82772ff8a9a1d86561823bd9
|
data/README.md
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# ActiveStorage::PostgreSQL
|
2
2
|
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/active_storage-postgresql.svg)](https://badge.fury.io/rb/active_storage-postgresql)
|
4
|
+
[![Build Status](https://travis-ci.com/lsylvester/active_storage-postgresql.svg?branch=master)](https://travis-ci.com/lsylvester/active_storage-postgresql)
|
5
|
+
|
3
6
|
ActiveStorage Service to store files PostgeSQL.
|
4
7
|
|
5
8
|
Files are stored in PostgreSQL as Large Objects, which provide streaming style access.
|
@@ -7,13 +10,13 @@ More information about Large Objects can be found [here](https://www.postgresql.
|
|
7
10
|
|
8
11
|
This allows use of ActiveStorage on hosting platforms with ephemeral file systems such as Heroku without relying on third party storage services.
|
9
12
|
|
10
|
-
There are [some limits](https://dba.stackexchange.com/questions/127270/what-are-the-limits-of-postgresqls-large-object-facility) to the storage of Large Objects in PostgerSQL, so this is only recommended for prototyping and very small sites.
|
13
|
+
There are [some limits](https://dba.stackexchange.com/questions/127270/what-are-the-limits-of-postgresqls-large-object-facility) to the storage of Large Objects in PostgerSQL, so this is only recommended for prototyping and very small sites.
|
11
14
|
|
12
15
|
## Installation
|
13
16
|
Add this line to your application's Gemfile:
|
14
17
|
|
15
18
|
```ruby
|
16
|
-
gem 'active_storage-postgresql'
|
19
|
+
gem 'active_storage-postgresql'
|
17
20
|
```
|
18
21
|
|
19
22
|
And then execute:
|
@@ -1,8 +1,31 @@
|
|
1
1
|
class ActiveStorage::PostgreSQL::File < ActiveRecord::Base
|
2
2
|
self.table_name = "active_storage_postgresql_files"
|
3
3
|
|
4
|
-
|
5
|
-
|
4
|
+
attribute :oid, :integer, default: ->{ connection.raw_connection.lo_creat }
|
5
|
+
attr_accessor :checksum, :io
|
6
|
+
attr_writer :digest
|
7
|
+
|
8
|
+
def digest
|
9
|
+
@digest ||= Digest::MD5.new
|
10
|
+
end
|
11
|
+
|
12
|
+
before_create :write_or_import, if: :io
|
13
|
+
before_create :verify_checksum, if: :checksum
|
14
|
+
|
15
|
+
def write_or_import
|
16
|
+
if io.respond_to?(:to_path)
|
17
|
+
import(io.to_path)
|
18
|
+
else
|
19
|
+
open(::PG::INV_WRITE) do |file|
|
20
|
+
while data = io.read(5.megabytes)
|
21
|
+
write(data)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def verify_checksum
|
28
|
+
raise ActiveStorage::IntegrityError unless digest.base64digest == checksum
|
6
29
|
end
|
7
30
|
|
8
31
|
def self.open(key, &block)
|
@@ -22,34 +45,40 @@ class ActiveStorage::PostgreSQL::File < ActiveRecord::Base
|
|
22
45
|
|
23
46
|
def write(content)
|
24
47
|
lo_write(@lo, content)
|
48
|
+
digest.update(content)
|
25
49
|
end
|
26
50
|
|
27
51
|
def read(bytes=size)
|
28
52
|
lo_read(@lo, bytes)
|
29
53
|
end
|
30
54
|
|
31
|
-
def seek(position)
|
32
|
-
lo_seek(@lo, position,
|
55
|
+
def seek(position, whence=PG::SEEK_SET)
|
56
|
+
lo_seek(@lo, position, whence)
|
33
57
|
end
|
34
58
|
|
35
59
|
def import(path)
|
36
|
-
|
37
|
-
|
38
|
-
|
60
|
+
self.oid = lo_import(path)
|
61
|
+
self.digest = Digest::MD5.file(path)
|
62
|
+
end
|
63
|
+
|
64
|
+
def tell
|
65
|
+
lo_tell(@lo)
|
39
66
|
end
|
40
67
|
|
41
68
|
def size
|
42
|
-
current_position =
|
43
|
-
|
44
|
-
|
45
|
-
|
69
|
+
current_position = tell
|
70
|
+
seek(0, PG::SEEK_END)
|
71
|
+
tell.tap do
|
72
|
+
seek(current_position)
|
46
73
|
end
|
47
74
|
end
|
48
75
|
|
49
|
-
|
50
|
-
|
76
|
+
def unlink
|
77
|
+
lo_unlink(oid)
|
51
78
|
end
|
52
79
|
|
80
|
+
before_destroy :unlink
|
81
|
+
|
53
82
|
delegate :lo_seek, :lo_tell, :lo_import, :lo_read, :lo_write, :lo_open,
|
54
83
|
:lo_unlink, :lo_close, :lo_creat, to: 'self.class.connection.raw_connection'
|
55
84
|
|
@@ -9,33 +9,9 @@ module ActiveStorage
|
|
9
9
|
def initialize(**options)
|
10
10
|
end
|
11
11
|
|
12
|
-
def upload(key, io, checksum: nil)
|
12
|
+
def upload(key, io, checksum: nil, **)
|
13
13
|
instrument :upload, key: key, checksum: checksum do
|
14
|
-
|
15
|
-
ActiveStorage::PostgreSQL::File.create!(key: key) do |file|
|
16
|
-
file.import(io.to_path)
|
17
|
-
end
|
18
|
-
if checksum
|
19
|
-
unless Digest::MD5.file(io.to_path).base64digest == checksum
|
20
|
-
delete key
|
21
|
-
raise ActiveStorage::IntegrityError
|
22
|
-
end
|
23
|
-
end
|
24
|
-
else
|
25
|
-
md5 = Digest::MD5.new
|
26
|
-
ActiveStorage::PostgreSQL::File.create!(key: key).open(::PG::INV_WRITE) do |file|
|
27
|
-
while data = io.read(5.megabytes)
|
28
|
-
md5.update(data)
|
29
|
-
file.write(data)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
if checksum
|
33
|
-
unless md5.base64digest == checksum
|
34
|
-
delete key
|
35
|
-
raise ActiveStorage::IntegrityError
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
14
|
+
ActiveStorage::PostgreSQL::File.create!(key: key, io: io, checksum: checksum)
|
39
15
|
end
|
40
16
|
end
|
41
17
|
|
@@ -88,17 +64,23 @@ module ActiveStorage
|
|
88
64
|
|
89
65
|
def url(key, expires_in:, filename:, disposition:, content_type:)
|
90
66
|
instrument :url, key: key do |payload|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
host: current_host,
|
97
|
-
filename: filename,
|
98
|
-
disposition: content_disposition_with(type: disposition, filename: filename),
|
67
|
+
content_disposition = content_disposition_with(type: disposition, filename: filename)
|
68
|
+
verified_key_with_expiration = ActiveStorage.verifier.generate(
|
69
|
+
{
|
70
|
+
key: key,
|
71
|
+
disposition: content_disposition,
|
99
72
|
content_type: content_type
|
100
|
-
|
73
|
+
},
|
74
|
+
{ expires_in: expires_in,
|
75
|
+
purpose: :blob_key }
|
76
|
+
)
|
101
77
|
|
78
|
+
generated_url = url_helpers.rails_disk_service_url(verified_key_with_expiration,
|
79
|
+
host: current_host,
|
80
|
+
disposition: content_disposition,
|
81
|
+
content_type: content_type,
|
82
|
+
filename: filename
|
83
|
+
)
|
102
84
|
payload[:url] = generated_url
|
103
85
|
|
104
86
|
generated_url
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_storage-postgresql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lachlan Sylvester
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-11-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -104,7 +104,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
104
104
|
version: '0'
|
105
105
|
requirements: []
|
106
106
|
rubyforge_project:
|
107
|
-
rubygems_version: 2.7.
|
107
|
+
rubygems_version: 2.7.6
|
108
108
|
signing_key:
|
109
109
|
specification_version: 4
|
110
110
|
summary: PostgreSQL Adapter for Active Storage
|