s3_relay 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/README.md +3 -19
- data/app/assets/javascripts/s3_relay.coffee +4 -4
- data/app/controllers/s3_relay/uploads_controller.rb +8 -2
- data/app/models/s3_relay/upload.rb +1 -1
- data/db/migrate/20141009000804_create_s3_relay_uploads.rb +1 -1
- data/lib/s3_relay/base.rb +1 -1
- data/lib/s3_relay/engine.rb +1 -1
- data/lib/s3_relay/private_url.rb +1 -1
- data/lib/s3_relay/version.rb +1 -1
- data/test/controllers/s3_relay/uploads_controller_test.rb +28 -22
- data/test/dummy/{README.rdoc → README.md} +1 -5
- data/test/dummy/Rakefile +1 -1
- data/test/dummy/app/assets/config/manifest.js +3 -0
- data/test/dummy/app/assets/javascripts/application.js +6 -4
- data/test/dummy/app/assets/javascripts/cable.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +5 -5
- data/test/dummy/app/channels/application_cable/channel.rb +4 -0
- data/test/dummy/app/channels/application_cable/connection.rb +4 -0
- data/test/dummy/app/controllers/application_controller.rb +0 -2
- data/test/dummy/app/jobs/application_job.rb +2 -0
- data/test/dummy/app/mailers/application_mailer.rb +4 -0
- data/test/dummy/app/models/application_record.rb +3 -0
- data/test/dummy/app/models/product.rb +1 -1
- data/test/dummy/app/views/layouts/application.html.erb +9 -9
- data/test/dummy/app/views/layouts/mailer.html.erb +13 -0
- data/test/dummy/app/views/layouts/mailer.text.erb +1 -0
- data/test/dummy/bin/rails +6 -1
- data/test/dummy/bin/rake +5 -0
- data/test/dummy/bin/setup +38 -0
- data/test/dummy/bin/spring +17 -0
- data/test/dummy/bin/update +29 -0
- data/test/dummy/bin/yarn +11 -0
- data/test/dummy/config.ru +2 -1
- data/test/dummy/config/application.rb +7 -11
- data/test/dummy/config/boot.rb +2 -4
- data/test/dummy/config/cable.yml +10 -0
- data/test/dummy/config/environment.rb +1 -1
- data/test/dummy/config/environments/development.rb +24 -7
- data/test/dummy/config/environments/production.rb +36 -23
- data/test/dummy/config/environments/test.rb +6 -3
- data/test/dummy/config/initializers/application_controller_renderer.rb +6 -0
- data/test/dummy/config/initializers/assets.rb +8 -2
- data/test/dummy/config/initializers/cookies_serializer.rb +3 -1
- data/test/dummy/config/initializers/wrap_parameters.rb +2 -2
- data/test/dummy/config/locales/en.yml +10 -0
- data/test/dummy/config/puma.rb +56 -0
- data/test/dummy/config/secrets.yml +15 -5
- data/test/dummy/config/spring.rb +6 -0
- data/test/dummy/db/migrate/20141021002149_create_products.rb +1 -1
- data/test/dummy/db/schema.rb +13 -14
- data/test/dummy/db/seeds.rb +7 -0
- data/test/dummy/log/development.log +60 -20
- data/test/dummy/log/test.log +10958 -856
- data/test/dummy/package.json +5 -0
- data/test/dummy/public/404.html +6 -6
- data/test/dummy/public/422.html +6 -6
- data/test/dummy/public/500.html +6 -6
- data/test/dummy/public/apple-touch-icon-precomposed.png +0 -0
- data/test/dummy/public/apple-touch-icon.png +0 -0
- data/test/dummy/public/robots.txt +1 -0
- data/test/dummy/test/application_system_test_case.rb +5 -0
- data/test/dummy/test/test_helper.rb +9 -0
- data/test/factories/products.rb +2 -2
- data/test/factories/uploads.rb +14 -7
- data/test/helpers/s3_relay/uploads_helper_test.rb +7 -4
- data/test/lib/s3_relay/model_test.rb +15 -15
- data/test/lib/s3_relay/private_url_test.rb +1 -1
- data/test/lib/s3_relay/upload_presigner_test.rb +9 -9
- data/test/models/s3_relay/upload_test.rb +25 -24
- data/test/test_helper.rb +2 -4
- metadata +110 -72
- data/test/dummy/config/initializers/session_store.rb +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 10af82cfd6dbeef7aa3a3aae7938a708a09c2953a5133f03980d09e993182acc
|
4
|
+
data.tar.gz: 1aa52906c7727233f0c41563d35c5c05efc1d12ea0f7257c43d6f0ceed512911
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ef9f94b3ad1589fa3a9b9a4f85a19bb6ed203671e0f8f5691e286cee2c2a5388fa421ccbc473f68f2ff0517972bce9f1e79c19f60d2c08d96bcdb0e3ace609ea
|
7
|
+
data.tar.gz: 546127e77ed7d20d5597ba35a2c14288bafcad9f75d66935e1fea840ad8d17923537ce3231c38d81091f144cb033234a29110cce4788e944def60f7122f8f35e
|
data/README.md
CHANGED
@@ -6,10 +6,12 @@
|
|
6
6
|
Enables direct file uploads to Amazon S3 and provides a flexible pattern for
|
7
7
|
your Rails app to asynchronously ingest the files.
|
8
8
|
|
9
|
+
**Note: If you are using Rails 5.2+ you should consider migrating to Active Storage as this gem will not be suppored for Rails 6+.**
|
10
|
+
|
9
11
|
## Overview
|
10
12
|
|
11
13
|
This Rails engine allows you to quickly implement direct uploads to Amazon S3
|
12
|
-
from your
|
14
|
+
from your Ruby on Rails application. It does not depend on any specific file
|
13
15
|
upload libraries, UI frameworks or AWS gems, like other solutions tend to.
|
14
16
|
|
15
17
|
It works by utilizing Amazon S3's
|
@@ -41,24 +43,6 @@ write to disk. S3 then decrypts and streams the files as they are downloaded.
|
|
41
43
|
file is permitted or if multiple are.
|
42
44
|
* Multiple files can upload concurrently to S3.
|
43
45
|
|
44
|
-
## Technology & Requirements
|
45
|
-
|
46
|
-
Uploads are made possible by use of the `FormData` object, defined in
|
47
|
-
[XMLHttpRequest Level 2](http://dev.w3.org/2006/webapi/XMLHttpRequest-2/).
|
48
|
-
Many people are broadly referring to this as being provided by HTML5, but
|
49
|
-
technically it's part of the aforementioned spec that browsers have been
|
50
|
-
adhering to for a couple of major versions now. Even IE, wuh?
|
51
|
-
|
52
|
-
The latest versions of all of the following are ideal, but here are the gem's
|
53
|
-
minimum requirements:
|
54
|
-
|
55
|
-
* Ruby 1.9.3+
|
56
|
-
* Rails 3.1+
|
57
|
-
* Modern versions of Chrome, Safari, FireFox or IE 10+
|
58
|
-
* Note: Progress bars are currently disabled in IE
|
59
|
-
* Note: IE <= 9 users will be instructed to upgrade their browser upon
|
60
|
-
selecting a file
|
61
|
-
|
62
46
|
## Demo
|
63
47
|
|
64
48
|
See a demo application using `s3_relay` [here](https://github.com/kjohnston/s3_relay-demo).
|
@@ -46,13 +46,13 @@ uploadFiles = (container) ->
|
|
46
46
|
uploadFile = (container, file) ->
|
47
47
|
fileName = file.name
|
48
48
|
|
49
|
-
# Assign unique
|
50
|
-
|
51
|
-
|
49
|
+
# Assign unique value to each request so Safari doesn't consolidate them
|
50
|
+
@s3r_upload_index ||= 0
|
51
|
+
@s3r_upload_index += 1
|
52
52
|
|
53
53
|
$.ajax
|
54
54
|
type: "GET"
|
55
|
-
url: "/s3_relay/uploads/new?
|
55
|
+
url: "/s3_relay/uploads/new?s3r_upload_index=#{s3r_upload_index}"
|
56
56
|
success: (data, status, xhr) ->
|
57
57
|
formData = new FormData()
|
58
58
|
xhr = new XMLHttpRequest()
|
@@ -11,7 +11,13 @@ class S3Relay::UploadsController < ApplicationController
|
|
11
11
|
@upload = S3Relay::Upload.new(upload_attrs)
|
12
12
|
|
13
13
|
if @upload.save
|
14
|
-
|
14
|
+
data = {
|
15
|
+
private_url: @upload.private_url,
|
16
|
+
parent_type: @upload.parent_type,
|
17
|
+
parent_id: @upload.parent_id,
|
18
|
+
user_id: user_attrs[:user_id]
|
19
|
+
}
|
20
|
+
render json: data, status: 201
|
15
21
|
else
|
16
22
|
render json: { errors: @upload.errors }, status: 422
|
17
23
|
end
|
@@ -55,7 +61,7 @@ class S3Relay::UploadsController < ApplicationController
|
|
55
61
|
end
|
56
62
|
|
57
63
|
def user_attrs
|
58
|
-
if respond_to?(:current_user) && (id = current_user
|
64
|
+
if respond_to?(:current_user) && (id = current_user&.id)
|
59
65
|
{ user_id: id }
|
60
66
|
else
|
61
67
|
{}
|
data/lib/s3_relay/base.rb
CHANGED
data/lib/s3_relay/engine.rb
CHANGED
data/lib/s3_relay/private_url.rb
CHANGED
@@ -4,7 +4,7 @@ module S3Relay
|
|
4
4
|
attr_reader :expires, :path
|
5
5
|
|
6
6
|
def initialize(uuid, file, options={})
|
7
|
-
filename = URI.
|
7
|
+
filename = Addressable::URI.escape(file).gsub("+", "%2B")
|
8
8
|
@path = [uuid, filename].join("/")
|
9
9
|
@expires = (options[:expires] || 10.minutes.from_now).to_i
|
10
10
|
end
|
data/lib/s3_relay/version.rb
CHANGED
@@ -22,20 +22,20 @@ module S3Relay
|
|
22
22
|
S3Relay::UploadPresigner.any_instance.stubs(:uuid).returns(uuid)
|
23
23
|
S3Relay::UploadPresigner.any_instance.stubs(:expires).returns(time)
|
24
24
|
|
25
|
-
get
|
25
|
+
get new_s3_relay_upload_url
|
26
26
|
assert_response 200
|
27
27
|
|
28
28
|
data = JSON.parse(response.body)
|
29
29
|
|
30
|
-
data["awsaccesskeyid"].must_equal "access-key-id"
|
31
|
-
data["x_amz_server_side_encryption"].must_equal "AES256"
|
32
|
-
data["key"].must_equal "#{uuid}/${filename}"
|
33
|
-
data["success_action_status"].must_equal "201"
|
34
|
-
data["acl"].must_equal "acl"
|
35
|
-
data["endpoint"].must_equal "https://
|
36
|
-
data["policy"].length.must_equal 380 # TODO: Improve this
|
37
|
-
data["signature"].length.must_equal 28 # TODO: Improve this
|
38
|
-
data["uuid"].must_equal uuid
|
30
|
+
_(data["awsaccesskeyid"]).must_equal "access-key-id"
|
31
|
+
_(data["x_amz_server_side_encryption"]).must_equal "AES256"
|
32
|
+
_(data["key"]).must_equal "#{uuid}/${filename}"
|
33
|
+
_(data["success_action_status"]).must_equal "201"
|
34
|
+
_(data["acl"]).must_equal "acl"
|
35
|
+
_(data["endpoint"]).must_equal "https://s3.region.amazonaws.com/bucket"
|
36
|
+
_(data["policy"].length).must_equal 380 # TODO: Improve this
|
37
|
+
_(data["signature"].length).must_equal 28 # TODO: Improve this
|
38
|
+
_(data["uuid"]).must_equal uuid
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
@@ -44,11 +44,12 @@ module S3Relay
|
|
44
44
|
describe "success" do
|
45
45
|
it do
|
46
46
|
assert_difference "S3Relay::Upload.count", 1 do
|
47
|
-
post :
|
47
|
+
post s3_relay_uploads_url, params: {
|
48
48
|
association: "photo_uploads",
|
49
49
|
uuid: SecureRandom.uuid,
|
50
50
|
filename: "cat.png",
|
51
51
|
content_type: "image/png"
|
52
|
+
}
|
52
53
|
end
|
53
54
|
|
54
55
|
assert_response 201
|
@@ -56,17 +57,18 @@ module S3Relay
|
|
56
57
|
|
57
58
|
describe "with parent attributes" do
|
58
59
|
describe "matching an object" do
|
59
|
-
before { @product =
|
60
|
+
before { @product = FactoryBot.create(:product) }
|
60
61
|
|
61
62
|
it do
|
62
63
|
assert_difference "@product.photo_uploads.count", 1 do
|
63
|
-
post :
|
64
|
+
post s3_relay_uploads_url, params: {
|
64
65
|
association: "photo_uploads",
|
65
66
|
uuid: SecureRandom.uuid,
|
66
67
|
filename: "cat.png",
|
67
68
|
content_type: "image/png",
|
68
69
|
parent_type: @product.class.to_s,
|
69
70
|
parent_id: @product.id.to_s
|
71
|
+
}
|
70
72
|
end
|
71
73
|
|
72
74
|
assert_response 201
|
@@ -76,40 +78,43 @@ module S3Relay
|
|
76
78
|
describe "not matching an object" do
|
77
79
|
it do
|
78
80
|
assert_difference "S3Relay::Upload.count" do
|
79
|
-
post :
|
81
|
+
post s3_relay_uploads_url, params: {
|
80
82
|
association: "photo_uploads",
|
81
83
|
uuid: SecureRandom.uuid,
|
82
84
|
filename: "cat.png",
|
83
85
|
content_type: "image/png",
|
84
86
|
parent_type: "Product",
|
85
87
|
parent_id: "10000000"
|
88
|
+
}
|
86
89
|
end
|
87
90
|
|
88
91
|
assert_response 201
|
92
|
+
body = JSON.parse(response.body)
|
89
93
|
|
90
|
-
|
91
|
-
|
94
|
+
assert body["parent_type"] == nil
|
95
|
+
assert body["parent_id"] == nil
|
92
96
|
end
|
93
97
|
end
|
94
98
|
|
95
99
|
describe "with a current_user" do
|
96
100
|
before do
|
97
101
|
@user = OpenStruct.new(id: 123)
|
98
|
-
|
102
|
+
UploadsController.any_instance.stubs(:current_user).returns(@user)
|
99
103
|
end
|
100
104
|
|
101
105
|
it "associates the upload with the user" do
|
102
106
|
assert_difference "S3Relay::Upload.count", 1 do
|
103
|
-
post :
|
107
|
+
post s3_relay_uploads_url, params: {
|
104
108
|
association: "photo_uploads",
|
105
109
|
uuid: SecureRandom.uuid,
|
106
110
|
filename: "cat.png",
|
107
111
|
content_type: "image/png"
|
112
|
+
}
|
108
113
|
end
|
109
114
|
|
110
115
|
assert_response 201
|
111
|
-
|
112
|
-
|
116
|
+
body = JSON.parse(response.body)
|
117
|
+
_(body["user_id"]).must_equal @user.id
|
113
118
|
end
|
114
119
|
end
|
115
120
|
|
@@ -119,15 +124,16 @@ module S3Relay
|
|
119
124
|
describe "error" do
|
120
125
|
it do
|
121
126
|
assert_no_difference "S3Relay::Upload.count" do
|
122
|
-
post :
|
127
|
+
post s3_relay_uploads_url, params: {
|
123
128
|
uuid: SecureRandom.uuid,
|
124
129
|
filename: "cat.png",
|
125
130
|
content_type: "image/png"
|
131
|
+
}
|
126
132
|
end
|
127
133
|
|
128
134
|
assert_response 422
|
129
135
|
|
130
|
-
JSON.parse(response.body)["errors"]["upload_type"]
|
136
|
+
_(JSON.parse(response.body)["errors"]["upload_type"])
|
131
137
|
.must_include "can't be blank"
|
132
138
|
end
|
133
139
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
# README
|
2
2
|
|
3
3
|
This README would normally document whatever steps are necessary to get the
|
4
4
|
application up and running.
|
@@ -22,7 +22,3 @@ Things you may want to cover:
|
|
22
22
|
* Deployment instructions
|
23
23
|
|
24
24
|
* ...
|
25
|
-
|
26
|
-
|
27
|
-
Please feel free to use a different markup language if you do not plan to run
|
28
|
-
<tt>rake doc:app</tt>.
|
data/test/dummy/Rakefile
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
2
2
|
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
3
3
|
|
4
|
-
|
4
|
+
require_relative 'config/application'
|
5
5
|
|
6
6
|
Rails.application.load_tasks
|
@@ -1,13 +1,15 @@
|
|
1
1
|
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
2
2
|
// listed below.
|
3
3
|
//
|
4
|
-
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts,
|
5
|
-
//
|
4
|
+
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, or any plugin's
|
5
|
+
// vendor/assets/javascripts directory can be referenced here using a relative path.
|
6
6
|
//
|
7
7
|
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
8
|
-
// compiled file.
|
8
|
+
// compiled file. JavaScript code in this file should be added after the last require_* statement.
|
9
9
|
//
|
10
|
-
// Read Sprockets README (https://github.com/
|
10
|
+
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
|
11
11
|
// about supported directives.
|
12
12
|
//
|
13
|
+
//= require rails-ujs
|
14
|
+
//= require turbolinks
|
13
15
|
//= require_tree .
|
@@ -0,0 +1,13 @@
|
|
1
|
+
// Action Cable provides the framework to deal with WebSockets in Rails.
|
2
|
+
// You can generate new channels where WebSocket features live using the `rails generate channel` command.
|
3
|
+
//
|
4
|
+
//= require action_cable
|
5
|
+
//= require_self
|
6
|
+
//= require_tree ./channels
|
7
|
+
|
8
|
+
(function() {
|
9
|
+
this.App || (this.App = {});
|
10
|
+
|
11
|
+
App.cable = ActionCable.createConsumer();
|
12
|
+
|
13
|
+
}).call(this);
|
@@ -2,13 +2,13 @@
|
|
2
2
|
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
3
|
* listed below.
|
4
4
|
*
|
5
|
-
* Any CSS and SCSS file within this directory, lib/assets/stylesheets,
|
6
|
-
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's
|
6
|
+
* vendor/assets/stylesheets directory can be referenced here using a relative path.
|
7
7
|
*
|
8
8
|
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
9
|
-
* compiled file so the styles you add here take precedence over styles defined in any
|
10
|
-
*
|
11
|
-
* file per style scope.
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
|
10
|
+
* files in this directory. Styles in this file should be added after the last require_* statement.
|
11
|
+
* It is generally better to create a new file per style scope.
|
12
12
|
*
|
13
13
|
*= require_tree .
|
14
14
|
*= require_self
|
@@ -1,14 +1,14 @@
|
|
1
1
|
<!DOCTYPE html>
|
2
2
|
<html>
|
3
|
-
<head>
|
4
|
-
|
5
|
-
|
6
|
-
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
|
7
|
-
<%= csrf_meta_tags %>
|
8
|
-
</head>
|
9
|
-
<body>
|
3
|
+
<head>
|
4
|
+
<title>Dummy</title>
|
5
|
+
<%= csrf_meta_tags %>
|
10
6
|
|
11
|
-
<%=
|
7
|
+
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
|
8
|
+
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
|
9
|
+
</head>
|
12
10
|
|
13
|
-
|
11
|
+
<body>
|
12
|
+
<%= yield %>
|
13
|
+
</body>
|
14
14
|
</html>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= yield %>
|