attachie 0.0.1 → 1.0.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 +48 -3
- data/attachie.gemspec +0 -1
- data/lib/attachie.rb +10 -1
- data/lib/attachie/fake_driver.rb +12 -0
- data/lib/attachie/file_driver.rb +12 -0
- data/lib/attachie/s3_driver.rb +16 -0
- data/lib/attachie/version.rb +1 -1
- data/spec/attachie/fake_driver_spec.rb +32 -18
- data/spec/attachie/file_driver_spec.rb +53 -25
- data/spec/attachie/s3_driver_spec.rb +87 -37
- data/spec/attachie_spec.rb +39 -6
- metadata +2 -17
- data/lib/attachie/swift_driver.rb +0 -66
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2a6322baba1a72a9869ed2cb50a2f58a890fed49a5b1fbfb57c6e358dfcce4b2
|
4
|
+
data.tar.gz: 7e95e247cf920af92fd51d32b21bf2d0a82a59af022cacc1343a2bb71612d5b7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ef797be58fb2573636f3cfc9de41fc1484cc8f6357488e7d1699ed5288a79b3c2ca0a51795ab825ce8941f05c69986dd84dd05b1861493ef74c8cc1afb5a1cd6
|
7
|
+
data.tar.gz: e986a15bc1a7781d4d60f620949582ae455c0dc6374c818930c7990a430bc9cbc4740d14cb2b0a60865769c084b7bc5bbce9c55f5aa1cabb0a10790704767745
|
data/README.md
CHANGED
@@ -36,6 +36,9 @@ class User
|
|
36
36
|
end
|
37
37
|
```
|
38
38
|
|
39
|
+
Please note, Attachie will interpolate colon prefixed segments like `:id` by
|
40
|
+
replacing it with the return value of the respective method.
|
41
|
+
|
39
42
|
Second, store blobs for your version:
|
40
43
|
|
41
44
|
```ruby
|
@@ -71,14 +74,15 @@ user.avatar(:icon).temp_url(expires_in: 2.days) # Must be supported by the drive
|
|
71
74
|
|
72
75
|
## Drivers
|
73
76
|
|
74
|
-
The `
|
77
|
+
The `Attachie` gem ships with the following drivers:
|
75
78
|
|
76
79
|
* `Attachie::FileDriver`: To store files on the local file system
|
77
80
|
* `Attachie::FakeDriver`: To store files in memory (for testing)
|
78
81
|
* `Attachie::S3Driver`: To store files on S3
|
79
|
-
* `Attachie::SwiftDriver`: To store files on an Openstack Swift provider
|
80
82
|
|
81
|
-
|
83
|
+
### FileDriver
|
84
|
+
|
85
|
+
To use the file driver:
|
82
86
|
|
83
87
|
```ruby
|
84
88
|
require "attachie/file_driver"
|
@@ -94,6 +98,47 @@ class User
|
|
94
98
|
end
|
95
99
|
```
|
96
100
|
|
101
|
+
### S3Driver
|
102
|
+
|
103
|
+
To use the s3 driver:
|
104
|
+
|
105
|
+
```ruby
|
106
|
+
require "attachie/s3_driver"
|
107
|
+
|
108
|
+
Attachie.default_options[:driver] = Attachie::S3Driver.new(Aws::S3::Client.new('...'))
|
109
|
+
```
|
110
|
+
|
111
|
+
### FakeDriver
|
112
|
+
|
113
|
+
To use the fake driver (useful for testing):
|
114
|
+
|
115
|
+
```ruby
|
116
|
+
require "attachie/fake_driver"
|
117
|
+
|
118
|
+
Attachie.default_options[:driver] = Attache::FakeDriver.new
|
119
|
+
```
|
120
|
+
|
121
|
+
Drivers and other options can be set on an attachment level as well:
|
122
|
+
|
123
|
+
```ruby
|
124
|
+
class User
|
125
|
+
include Attachie
|
126
|
+
|
127
|
+
attachment :avatar, driver: MyFileDriver, versions: {
|
128
|
+
# ...
|
129
|
+
}
|
130
|
+
end
|
131
|
+
```
|
132
|
+
|
133
|
+
## Direct S3 Uploads
|
134
|
+
|
135
|
+
Attachie allows to presign s3 post requests like:
|
136
|
+
|
137
|
+
```ruby
|
138
|
+
user.avatar(:icon).presign_post(content_type: 'image/jpeg', ...)
|
139
|
+
# => {"fields"=>{"key"=>"path/to/object","x-amz-signature"=>"..."},"headers":{},"method"=>"post","url"=>"..."}
|
140
|
+
```
|
141
|
+
|
97
142
|
## Contributing
|
98
143
|
|
99
144
|
1. Fork it ( https://github.com/mrkamel/attachie/fork )
|
data/attachie.gemspec
CHANGED
@@ -18,7 +18,6 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.add_dependency "swift_client"
|
22
21
|
spec.add_dependency "aws-sdk-s3"
|
23
22
|
spec.add_dependency "mime-types"
|
24
23
|
spec.add_dependency "connection_pool"
|
data/lib/attachie.rb
CHANGED
@@ -7,6 +7,7 @@ module Attachie
|
|
7
7
|
class UnknownAttachment < StandardError; end
|
8
8
|
class NoSuchVersion < StandardError; end
|
9
9
|
class InterpolationError < StandardError; end
|
10
|
+
class NotSupported < StandardError; end
|
10
11
|
|
11
12
|
def self.default_options
|
12
13
|
@default_options ||= { :protocol => "http" }
|
@@ -22,6 +23,10 @@ module Attachie
|
|
22
23
|
self.options = options
|
23
24
|
end
|
24
25
|
|
26
|
+
def presigned_post(options = {})
|
27
|
+
option(:driver).presigned_post(path, container, options)
|
28
|
+
end
|
29
|
+
|
25
30
|
def url
|
26
31
|
"#{interpolate option(:protocol)}://#{interpolate option(:host)}/#{interpolate(option(:url_prefix)).to_s + "/" if option(:url_prefix)}#{path}#{interpolate(option(:url_suffix)) if option(:url_suffix)}"
|
27
32
|
end
|
@@ -54,6 +59,10 @@ module Attachie
|
|
54
59
|
option(:driver).store(path, data_or_io, container, opts)
|
55
60
|
end
|
56
61
|
|
62
|
+
def info
|
63
|
+
option(:driver).info(path, container)
|
64
|
+
end
|
65
|
+
|
57
66
|
def store_multipart(opts = {}, &block)
|
58
67
|
option(:driver).store_multipart(path, container, opts, &block)
|
59
68
|
end
|
@@ -148,7 +157,7 @@ module Attachie
|
|
148
157
|
|
149
158
|
raise(UnknownAttachment) unless definition
|
150
159
|
|
151
|
-
Attachment.new
|
160
|
+
Attachment.new(self, name, definition)
|
152
161
|
end
|
153
162
|
|
154
163
|
module ClassMethods
|
data/lib/attachie/fake_driver.rb
CHANGED
@@ -42,6 +42,18 @@ module Attachie
|
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
+
def info(name, bucket)
|
46
|
+
{
|
47
|
+
last_modified: nil,
|
48
|
+
content_length: objects(bucket)[name].size,
|
49
|
+
content_type: MIME::Types.of(name).first&.to_s
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
def presigned_post(name, bucket, options = {})
|
54
|
+
raise NotSupported, 'presigned_post is not supported in FakeDriver'
|
55
|
+
end
|
56
|
+
|
45
57
|
def store(name, data_or_io, bucket, options = {})
|
46
58
|
objects(bucket)[name] = data_or_io.respond_to?(:read) ? data_or_io.read : data_or_io
|
47
59
|
end
|
data/lib/attachie/file_driver.rb
CHANGED
@@ -65,6 +65,18 @@ module Attachie
|
|
65
65
|
true
|
66
66
|
end
|
67
67
|
|
68
|
+
def presigned_post(name, bucket, options = {})
|
69
|
+
raise NotSupported, 'presigned_post is not supported in FileDriver'
|
70
|
+
end
|
71
|
+
|
72
|
+
def info(name, bucket)
|
73
|
+
{
|
74
|
+
last_modified: File.mtime(path_for(name, bucket)),
|
75
|
+
content_type: MIME::Types.of(name).first&.to_s,
|
76
|
+
content_length: File.size(path_for(name, bucket))
|
77
|
+
}
|
78
|
+
end
|
79
|
+
|
68
80
|
def store_multipart(name, bucket, options = {}, &block)
|
69
81
|
path = path_for(name, bucket)
|
70
82
|
|
data/lib/attachie/s3_driver.rb
CHANGED
@@ -59,6 +59,12 @@ module Attachie
|
|
59
59
|
self.s3_resource = Aws::S3::Resource.new(client: s3_client)
|
60
60
|
end
|
61
61
|
|
62
|
+
def presigned_post(name, bucket, options = {})
|
63
|
+
res = s3_resource.bucket(bucket).object(name).presigned_post(options)
|
64
|
+
|
65
|
+
return { fields: res.fields, headers: {}, method: "post", url: res.url }
|
66
|
+
end
|
67
|
+
|
62
68
|
def list(bucket, prefix: nil)
|
63
69
|
return enum_for(:list, bucket, prefix: prefix) unless block_given?
|
64
70
|
|
@@ -70,6 +76,16 @@ module Attachie
|
|
70
76
|
end
|
71
77
|
end
|
72
78
|
|
79
|
+
def info(name, bucket)
|
80
|
+
object = s3_resource.bucket(bucket).object(name)
|
81
|
+
|
82
|
+
{
|
83
|
+
content_length: object.content_length,
|
84
|
+
last_modified: object.last_modified,
|
85
|
+
content_type: object.content_type
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
73
89
|
def store(name, data_or_io, bucket, options = {})
|
74
90
|
opts = options.dup
|
75
91
|
|
data/lib/attachie/version.rb
CHANGED
@@ -4,32 +4,36 @@ require File.expand_path("../../spec_helper", __FILE__)
|
|
4
4
|
RSpec.describe Attachie::FakeDriver do
|
5
5
|
let(:driver) { Attachie::FakeDriver.new }
|
6
6
|
|
7
|
-
|
8
|
-
|
7
|
+
after { driver.flush }
|
8
|
+
|
9
|
+
describe "#presigned_post" do
|
10
|
+
it "raises NotSupported" do
|
11
|
+
expect { driver.presigned_post("path", "bucket") }.to raise_error(Attachie::NotSupported)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#list" do
|
16
|
+
it "lists objects" do
|
9
17
|
driver.store("object1", "blob", "bucket1")
|
10
18
|
driver.store("object2", "blob", "bucket1")
|
11
19
|
driver.store("other", "blob", "bucket1")
|
12
20
|
driver.store("object", "blob", "bucket3")
|
13
21
|
|
14
22
|
expect(driver.list("bucket1", prefix: "object").to_a).to eq(["object1", "object2"])
|
15
|
-
ensure
|
16
|
-
driver.flush
|
17
23
|
end
|
18
24
|
end
|
19
25
|
|
20
|
-
|
21
|
-
|
26
|
+
describe "#store" do
|
27
|
+
it "stores a blob" do
|
22
28
|
driver.store("name", "blob", "bucket")
|
23
29
|
|
24
30
|
expect(driver.exists?("name", "bucket")).to be(true)
|
25
31
|
expect(driver.value("name", "bucket")).to eq("blob")
|
26
|
-
ensure
|
27
|
-
driver.flush
|
28
32
|
end
|
29
33
|
end
|
30
34
|
|
31
|
-
|
32
|
-
|
35
|
+
describe "#store_multipart" do
|
36
|
+
it "stores a blob via multipart upload" do
|
33
37
|
driver.store_multipart("name", "bucket") do |upload|
|
34
38
|
upload.upload_part("chunk1")
|
35
39
|
upload.upload_part("chunk2")
|
@@ -37,25 +41,35 @@ RSpec.describe Attachie::FakeDriver do
|
|
37
41
|
|
38
42
|
expect(driver.exists?("name", "bucket")).to be(true)
|
39
43
|
expect(driver.value("name", "bucket")).to eq("chunk1chunk2")
|
40
|
-
ensure
|
41
|
-
driver.flush
|
42
44
|
end
|
43
45
|
end
|
44
46
|
|
45
|
-
|
46
|
-
|
47
|
+
describe "#delete" do
|
48
|
+
it "deletes a blob" do
|
47
49
|
driver.store("name", "blob", "bucket")
|
48
50
|
expect(driver.exists?("name", "bucket")).to be(true)
|
49
51
|
|
50
52
|
driver.delete("name", "bucket")
|
51
53
|
expect(driver.exists?("name", "bucket")).to be(false)
|
52
|
-
ensure
|
53
|
-
driver.flush
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
57
|
-
|
58
|
-
|
57
|
+
describe "#temp_url" do
|
58
|
+
it "generates a temp_url" do
|
59
|
+
expect(driver.temp_url("name", "bucket")).to eq("https://example.com/bucket/name?signature=signature&expires=expires")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "#info" do
|
64
|
+
it "returns info about the object" do
|
65
|
+
driver.store("name.txt", "blob", "bucket")
|
66
|
+
|
67
|
+
expect(driver.info("name.txt", "bucket")).to eq(
|
68
|
+
content_length: 4,
|
69
|
+
content_type: "text/plain",
|
70
|
+
last_modified: nil
|
71
|
+
)
|
72
|
+
end
|
59
73
|
end
|
60
74
|
end
|
61
75
|
|
@@ -4,40 +4,68 @@ require File.expand_path("../../spec_helper", __FILE__)
|
|
4
4
|
RSpec.describe Attachie::FileDriver do
|
5
5
|
let(:driver) { Attachie::FileDriver.new("/tmp/attachie") }
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
driver.
|
10
|
-
|
11
|
-
expect(driver.exists?("name", "bucket")).to be(true)
|
12
|
-
expect(driver.value("name", "bucket")).to eq("blob")
|
13
|
-
ensure
|
14
|
-
driver.delete("name", "bucket")
|
7
|
+
describe "#presigned_post" do
|
8
|
+
it "raises NotSupported" do
|
9
|
+
expect { driver.presigned_post("path", "bucket") }.to raise_error(Attachie::NotSupported)
|
15
10
|
end
|
16
11
|
end
|
17
12
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
13
|
+
describe "#store" do
|
14
|
+
it "stores a blob" do
|
15
|
+
begin
|
16
|
+
driver.store("name", "blob", "bucket")
|
17
|
+
|
18
|
+
expect(driver.exists?("name", "bucket")).to be(true)
|
19
|
+
expect(driver.value("name", "bucket")).to eq("blob")
|
20
|
+
ensure
|
21
|
+
driver.delete("name", "bucket")
|
23
22
|
end
|
23
|
+
end
|
24
|
+
end
|
24
25
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
26
|
+
describe" #store_multipart" do
|
27
|
+
it "stores a blob via multipart upload" do
|
28
|
+
begin
|
29
|
+
driver.store_multipart("name", "bucket") do |upload|
|
30
|
+
upload.upload_part("chunk1")
|
31
|
+
upload.upload_part("chunk2")
|
32
|
+
end
|
33
|
+
|
34
|
+
expect(driver.exists?("name", "bucket")).to be(true)
|
35
|
+
expect(driver.value("name", "bucket")).to eq("chunk1chunk2")
|
36
|
+
ensure
|
37
|
+
driver.delete("name", "bucket")
|
38
|
+
end
|
29
39
|
end
|
30
40
|
end
|
31
41
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
42
|
+
describe "#delete" do
|
43
|
+
it "deletes a blob" do
|
44
|
+
begin
|
45
|
+
driver.store("name", "blob", "bucket")
|
46
|
+
expect(driver.exists?("name", "bucket")).to be(true)
|
36
47
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
48
|
+
driver.delete("name", "bucket")
|
49
|
+
expect(driver.exists?("name", "bucket")).to be(false)
|
50
|
+
ensure
|
51
|
+
driver.delete("name", "bucket")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "#info" do
|
57
|
+
it "returns info about the object" do
|
58
|
+
begin
|
59
|
+
driver.store("name.txt", "blob", "bucket")
|
60
|
+
|
61
|
+
expect(driver.info("name.txt", "bucket")).to match(
|
62
|
+
content_length: 4,
|
63
|
+
content_type: "text/plain",
|
64
|
+
last_modified: anything
|
65
|
+
)
|
66
|
+
ensure
|
67
|
+
driver.delete("name.txt", "bucket")
|
68
|
+
end
|
41
69
|
end
|
42
70
|
end
|
43
71
|
end
|
@@ -11,59 +11,109 @@ RSpec.describe Attachie::S3Driver do
|
|
11
11
|
))
|
12
12
|
end
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
14
|
+
describe "#list" do
|
15
|
+
it "lists objects" do
|
16
|
+
begin
|
17
|
+
driver.store("object1", "blob", "bucket")
|
18
|
+
driver.store("object2", "blob", "bucket")
|
19
|
+
driver.store("other", "blob", "bucket")
|
20
|
+
|
21
|
+
expect(driver.list("bucket", prefix: "object").to_a).to eq(["object1", "object2"])
|
22
|
+
ensure
|
23
|
+
driver.delete("object1", "bucket")
|
24
|
+
driver.delete("object2", "bucket")
|
25
|
+
driver.delete("other", "bucket")
|
26
|
+
end
|
25
27
|
end
|
26
28
|
end
|
27
29
|
|
28
|
-
|
29
|
-
|
30
|
-
|
30
|
+
describe "#store" do
|
31
|
+
it "stores a blob" do
|
32
|
+
begin
|
33
|
+
driver.store("name", "blob", "bucket")
|
31
34
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
35
|
+
expect(driver.exists?("name", "bucket")).to be(true)
|
36
|
+
expect(driver.value("name", "bucket")).to eq("blob")
|
37
|
+
ensure
|
38
|
+
driver.delete("name", "bucket")
|
39
|
+
end
|
36
40
|
end
|
37
41
|
end
|
38
42
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
43
|
+
describe "#store_multipart" do
|
44
|
+
it "stores a blob via multipart upload" do
|
45
|
+
begin
|
46
|
+
driver.store_multipart("name", "bucket") do |upload|
|
47
|
+
upload.upload_part("chunk1")
|
48
|
+
upload.upload_part("chunk2")
|
49
|
+
end
|
50
|
+
|
51
|
+
expect(driver.exists?("name", "bucket")).to be(true)
|
52
|
+
expect(driver.value("name", "bucket")).to eq("chunk1chunk2")
|
53
|
+
ensure
|
54
|
+
driver.delete("name", "bucket")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "#delete" do
|
60
|
+
it "deletes a blob" do
|
61
|
+
begin
|
62
|
+
driver.store("name", "blob", "bucket")
|
63
|
+
expect(driver.exists?("name", "bucket")).to be(true)
|
64
|
+
|
65
|
+
driver.delete("name", "bucket")
|
66
|
+
expect(driver.exists?("name", "bucket")).to be(false)
|
67
|
+
ensure
|
68
|
+
driver.delete("name", "bucket")
|
44
69
|
end
|
70
|
+
end
|
71
|
+
end
|
45
72
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
driver.delete("name", "bucket")
|
73
|
+
describe "#temp_url" do
|
74
|
+
it "generates a temp_url" do
|
75
|
+
expect(driver.temp_url("name", "bucket")).to be_url
|
50
76
|
end
|
51
77
|
end
|
52
78
|
|
53
|
-
|
54
|
-
|
55
|
-
driver.
|
56
|
-
|
79
|
+
describe "#presigned_post" do
|
80
|
+
it "generates a presign response" do
|
81
|
+
expect(driver.presigned_post("path/to/object", "bucket")).to match(
|
82
|
+
fields: hash_including("key" => "path/to/object"),
|
83
|
+
headers: {},
|
84
|
+
method: "post",
|
85
|
+
url: "http://bucket.localhost:4569"
|
86
|
+
)
|
87
|
+
end
|
88
|
+
|
89
|
+
it "supports and passes additional options" do
|
90
|
+
bucket = double
|
91
|
+
object = double
|
92
|
+
|
93
|
+
allow(bucket).to receive(:object).and_return(object)
|
94
|
+
allow(object).to receive(:presigned_post).and_return(OpenStruct.new)
|
95
|
+
allow(driver.s3_resource).to receive(:bucket).and_return(bucket)
|
57
96
|
|
58
|
-
driver.
|
59
|
-
|
60
|
-
|
61
|
-
driver.delete("name", "bucket")
|
97
|
+
driver.presigned_post("path", "bucket", { key: "value" })
|
98
|
+
|
99
|
+
expect(object).to have_received(:presigned_post).with(hash_including(key: "value"))
|
62
100
|
end
|
63
101
|
end
|
64
102
|
|
65
|
-
|
66
|
-
|
103
|
+
describe "#info" do
|
104
|
+
it "returns info about the object" do
|
105
|
+
begin
|
106
|
+
driver.store("name.txt", "blob", "bucket")
|
107
|
+
|
108
|
+
expect(driver.info("name.txt", "bucket")).to match(
|
109
|
+
content_length: 4,
|
110
|
+
content_type: "text/plain",
|
111
|
+
last_modified: anything
|
112
|
+
)
|
113
|
+
ensure
|
114
|
+
driver.delete("name.txt", "bucket")
|
115
|
+
end
|
116
|
+
end
|
67
117
|
end
|
68
118
|
end
|
69
119
|
|
data/spec/attachie_spec.rb
CHANGED
@@ -17,32 +17,32 @@ class TestModel
|
|
17
17
|
end
|
18
18
|
|
19
19
|
RSpec.describe TestModel do
|
20
|
-
it "
|
20
|
+
it "interpolates the path" do
|
21
21
|
test_model = TestModel.new(filename: "file.jpg")
|
22
22
|
|
23
23
|
expect(test_model.file(:small).path).to eq("path/to/small/file.jpg")
|
24
24
|
end
|
25
25
|
|
26
|
-
it "
|
26
|
+
it "allows arbitrary version methods" do
|
27
27
|
test_model = TestModel.new(filename: "file.jpg")
|
28
28
|
|
29
29
|
expect(test_model.file(:small).attribute).to eq("value")
|
30
30
|
end
|
31
31
|
|
32
|
-
it "
|
32
|
+
it "respects the host" do
|
33
33
|
test_model = TestModel.new(filename: "file.jpg")
|
34
34
|
|
35
35
|
expect(test_model.file(:large).url).to eq("http://www.example.com/path/to/large/file.jpg")
|
36
36
|
end
|
37
37
|
|
38
|
-
it "
|
38
|
+
it "correctly uses the driver" do
|
39
39
|
test_model = TestModel.new(filename: "blob.txt")
|
40
40
|
test_model.file(:large).store "blob"
|
41
41
|
|
42
42
|
expect(test_model.file(:large).value).to eq("blob")
|
43
43
|
end
|
44
44
|
|
45
|
-
it "
|
45
|
+
it "sets updated_at" do
|
46
46
|
test_model = TestModel.new(filename: "file.jpg")
|
47
47
|
test_model.file = "file"
|
48
48
|
|
@@ -53,5 +53,38 @@ RSpec.describe TestModel do
|
|
53
53
|
|
54
54
|
expect(test_model.updated_at).to be_nil
|
55
55
|
end
|
56
|
-
end
|
57
56
|
|
57
|
+
describe "#info" do
|
58
|
+
it "returns info about the attachment" do
|
59
|
+
test_model = TestModel.new(filename: "blob.txt")
|
60
|
+
test_model.file(:large).store("blob")
|
61
|
+
|
62
|
+
expect(test_model.file(:large).info).to match(
|
63
|
+
last_modified: anything,
|
64
|
+
content_type: anything,
|
65
|
+
content_length: anything
|
66
|
+
)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "#presigned_post" do
|
71
|
+
let(:attachment) { TestModel.new(filename: "file.jpg").file(:large) }
|
72
|
+
let(:driver) { TestModel.attachments[:file][:driver] }
|
73
|
+
|
74
|
+
before do
|
75
|
+
allow(driver).to receive(:presigned_post)
|
76
|
+
end
|
77
|
+
|
78
|
+
it "delegates to the driver" do
|
79
|
+
attachment.presigned_post
|
80
|
+
|
81
|
+
expect(driver).to have_received(:presigned_post).with(attachment.path, attachment.bucket, {})
|
82
|
+
end
|
83
|
+
|
84
|
+
it "passes the supplied options" do
|
85
|
+
attachment.presigned_post(key: "value")
|
86
|
+
|
87
|
+
expect(driver).to have_received(:presigned_post).with(attachment.path, attachment.bucket, { key: "value" })
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
metadata
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: attachie
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Benjamin Vetter
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-11-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: swift_client
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ">="
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - ">="
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
27
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: aws-sdk-s3
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -156,7 +142,6 @@ files:
|
|
156
142
|
- lib/attachie/file_driver.rb
|
157
143
|
- lib/attachie/interpolation.rb
|
158
144
|
- lib/attachie/s3_driver.rb
|
159
|
-
- lib/attachie/swift_driver.rb
|
160
145
|
- lib/attachie/version.rb
|
161
146
|
- spec/attachie/fake_driver_spec.rb
|
162
147
|
- spec/attachie/file_driver_spec.rb
|
@@ -1,66 +0,0 @@
|
|
1
|
-
|
2
|
-
require "swift_client"
|
3
|
-
require "connection_pool"
|
4
|
-
|
5
|
-
module Attachie
|
6
|
-
class SwiftDriver
|
7
|
-
attr_accessor :swift_client_pool
|
8
|
-
|
9
|
-
def initialize(swift_client_pool)
|
10
|
-
self.swift_client_pool = swift_client_pool
|
11
|
-
end
|
12
|
-
|
13
|
-
def list(container, prefix: nil)
|
14
|
-
return enum_for(:list, container, prefix: prefix) unless block_given?
|
15
|
-
|
16
|
-
swift_client_pool.with do |swift_client|
|
17
|
-
swift_client.paginate_objects(container, prefix: prefix) do |response|
|
18
|
-
response.parsed_response.each do |source_object|
|
19
|
-
yield source_object["name"]
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def store(name, data_or_io, container, headers = {})
|
26
|
-
swift_client_pool.with do |swift_client|
|
27
|
-
swift_client.put_object name, data_or_io, container, headers
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def value(name, container)
|
32
|
-
swift_client_pool.with do |swift_client|
|
33
|
-
swift_client.get_object(name, container).body
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def delete(name, container)
|
38
|
-
swift_client_pool.with do |swift_client|
|
39
|
-
swift_client.delete_object name, container
|
40
|
-
end
|
41
|
-
rescue SwiftClient::ResponseError => e
|
42
|
-
return true if e.code == 404
|
43
|
-
|
44
|
-
raise e
|
45
|
-
end
|
46
|
-
|
47
|
-
def exists?(name, container)
|
48
|
-
swift_client_pool.with do |swift_client|
|
49
|
-
swift_client.head_object name, container
|
50
|
-
end
|
51
|
-
|
52
|
-
true
|
53
|
-
rescue SwiftClient::ResponseError => e
|
54
|
-
return false if e.code == 404
|
55
|
-
|
56
|
-
raise e
|
57
|
-
end
|
58
|
-
|
59
|
-
def temp_url(name, container, options = {})
|
60
|
-
swift_client_pool.with do |swift_client|
|
61
|
-
swift_client.temp_url name, container, options
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|