rails-uploader 0.2.8 → 0.3.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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +162 -86
  4. data/app/assets/javascripts/uploader/application.js +6 -4
  5. data/app/assets/javascripts/uploader/jquery.uploader.js.coffee +58 -0
  6. data/app/controllers/uploader/attachments_controller.rb +63 -39
  7. data/app/views/uploader/default/_container.html.erb +19 -45
  8. data/app/views/uploader/default/_download.html.erb +4 -5
  9. data/app/views/uploader/default/_upload.html.erb +0 -1
  10. data/config/locales/en.yml +2 -0
  11. data/config/locales/ru.yml +3 -0
  12. data/config/locales/uk.yml +3 -0
  13. data/config/routes.rb +1 -1
  14. data/lib/uploader/asset.rb +63 -84
  15. data/lib/uploader/authorization.rb +52 -0
  16. data/lib/uploader/authorization_adapter.rb +24 -0
  17. data/lib/uploader/chunked_uploads.rb +15 -0
  18. data/lib/uploader/engine.rb +6 -0
  19. data/lib/uploader/file_part.rb +18 -0
  20. data/lib/uploader/fileuploads.rb +42 -65
  21. data/lib/uploader/helpers/field_tag.rb +10 -5
  22. data/lib/uploader/hooks/formtastic.rb +0 -13
  23. data/lib/uploader/upload_request.rb +72 -0
  24. data/lib/uploader/version.rb +1 -1
  25. data/lib/uploader.rb +41 -8
  26. data/spec/dummy/app/models/asset.rb +12 -0
  27. data/spec/dummy/app/models/picture.rb +6 -0
  28. data/spec/dummy/db/test.sqlite3 +0 -0
  29. data/spec/dummy/log/test.log +325 -0
  30. data/spec/dummy/public/uploads/picture/data/1/thumb_rails.png +0 -0
  31. data/spec/dummy/public/uploads/picture/data/3/thumb_rails.png +0 -0
  32. data/spec/fileuploads_spec.rb +4 -4
  33. data/spec/requests/attachments_controller_spec.rb +11 -12
  34. data/vendor/assets/javascripts/uploader/jquery.fileupload-process.js +175 -0
  35. data/vendor/assets/javascripts/uploader/jquery.fileupload-ui.js +164 -261
  36. data/vendor/assets/javascripts/uploader/jquery.fileupload-validate.js +122 -0
  37. data/vendor/assets/javascripts/uploader/jquery.fileupload.js +335 -101
  38. data/vendor/assets/javascripts/uploader/jquery.iframe-transport.js +47 -15
  39. data/vendor/assets/javascripts/uploader/vendor/jquery.ui.widget.js +572 -0
  40. data/vendor/assets/javascripts/uploader/vendor/tmpl.min.js +1 -0
  41. data/vendor/assets/stylesheets/uploader/default.css +26 -19
  42. metadata +12 -9
  43. data/vendor/assets/javascripts/uploader/jquery.fileupload-fp.js +0 -227
  44. data/vendor/assets/javascripts/uploader/jquery.ui.widget.js +0 -530
  45. data/vendor/assets/javascripts/uploader/load-image.min.js +0 -1
  46. data/vendor/assets/javascripts/uploader/locales/en.js +0 -27
  47. data/vendor/assets/javascripts/uploader/locales/ru.js +0 -27
  48. data/vendor/assets/javascripts/uploader/locales/uk.js +0 -27
  49. data/vendor/assets/javascripts/uploader/tmpl.min.js +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 88c10bdc5c1c64828bf15e99962dee2c0e547eea
4
- data.tar.gz: 00ad13f2236fa9751d588bfac7275578dab4bd99
3
+ metadata.gz: 78c6ab34d67ec73bf7b3d802e186d3a179d7a25e
4
+ data.tar.gz: e76947d90bd1f5c0ea024a3939a0565ab7088477
5
5
  SHA512:
6
- metadata.gz: 637a0ecdea91d3edabb08bb572a7a7739ae97ea6a2d8a8cbe76c724c64836c39fef17f9d6b94e96148a8f7a72bd685ea9c7615e48270e715a0e38d4e29bff136
7
- data.tar.gz: 6cda451daaf4e3d7a5728dcfe49c2cf5e9b8fa07e78e76128fd3d50bc82ad45f5178ae1a15f6a57dc703d7907e321a19a8e4c8cb07d3c6a3d85fafd2e26fe0d6
6
+ metadata.gz: 34b3d48312fd023264a053d7c7c669dd6da137701b33c288c8e18f90bc70218d1e467f48c84673f60738f84aaec8f50a3490ff5d665587428a781ea23a73c327
7
+ data.tar.gz: 25737d84ebc664c361195c97b380a694297a96c9c7d5d299187cf898404ceaf8f74080f6c03cb93b77e711755b43352c5d6b9b79b66cf4a0d9127e7825d932dc
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright 2012 Fodojo http://fodojo.com/
1
+ Copyright 2016 Fodojo LLC http://fodojo.com/
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -2,16 +2,12 @@
2
2
 
3
3
  This gem use https://github.com/blueimp/jQuery-File-Upload for upload files.
4
4
 
5
- Preview:
6
-
7
- ![Uploader in use](http://img39.imageshack.us/img39/2206/railsuploader.png)
8
-
9
5
  ## Install
10
6
 
11
7
  In Gemfile:
12
8
 
13
9
  ```
14
- gem "rails-uploader"
10
+ gem 'rails-uploader'
15
11
  ```
16
12
 
17
13
  In routes:
@@ -33,44 +29,14 @@ Architecture to store uploaded files (cancan integration):
33
29
  ``` ruby
34
30
  class Asset < ActiveRecord::Base
35
31
  include Uploader::Asset
36
-
37
- def uploader_create(params, request = nil)
38
- ability = Ability.new(request.env['warden'].user)
39
-
40
- if ability.can? :create, self
41
- self.user = request.env['warden'].user
42
- super
43
- else
44
- errors.add(:id, :access_denied)
45
- end
46
- end
47
-
48
- def uploader_destroy(params, request = nil)
49
- ability = Ability.new(request.env['warden'].user)
50
-
51
- if ability.can? :delete, self
52
- super
53
- else
54
- errors.add(:id, :access_denied)
55
- end
56
- end
57
32
  end
58
33
 
59
34
  class Picture < Asset
60
- mount_uploader :data, PictureUploader
61
-
62
- validates_integrity_of :data
63
- validates_filesize_of :data, :maximum => 2.megabytes.to_i
35
+ mount_uploader :data, PictureUploader, mount_on: :data_file_name
36
+ validates :data, file_size: { maximum: 5.megabytes.to_i }
64
37
 
65
- # structure of returned json array of files. (used in Hash.to_json operation)
66
- def serializable_hash(options=nil)
67
- {
68
- "id" => id.to_s,
69
- "filename" => File.basename(data.path),
70
- "url" => data.url,
71
- "thumb_url" => data.url(:thumb),
72
- "public_token" => public_token
73
- }
38
+ def thumb_url
39
+ url(:thumb)
74
40
  end
75
41
  end
76
42
  ```
@@ -79,12 +45,9 @@ For example user has one picture:
79
45
 
80
46
  ``` ruby
81
47
  class User < ActiveRecord::Base
82
- has_one :picture, :as => :assetable, :dependent => :destroy
48
+ has_one :picture, as: :assetable, dependent: :destroy
83
49
 
84
50
  fileuploads :picture
85
-
86
- # If your don't use strong_parameters, uncomment next line
87
- # attr_accessible :fileupload_guid
88
51
  end
89
52
  ```
90
53
 
@@ -94,45 +57,6 @@ Find asset by foreign key or guid:
94
57
  @user.fileupload_asset(:picture)
95
58
  ```
96
59
 
97
- ### Mongoid
98
-
99
- No parent asset model is required, one only has to `include Uploader::Asset::Mongoid` into the
100
- model that should act like an asset:
101
-
102
- ``` ruby
103
- class Picture
104
- include Mongoid::Document
105
- include Uploader::Asset::Mongoid
106
-
107
- belongs_to :user
108
- end
109
-
110
- class User
111
- include Mongoid::Document
112
- include Uploader::Fileuploads
113
-
114
- has_one :picture, :as => :assetable
115
-
116
- fileuploads :picture
117
- end
118
- ```
119
-
120
- ### Notice
121
-
122
- User method fileuploads only once pre model. So if you have many attached files, use this:
123
-
124
- ``` ruby
125
- class User
126
- include Uploader::Fileuploads
127
-
128
- has_one :picture, :as => :assetable
129
- has_one :avatar, :as => :assetable
130
-
131
- fileuploads :picture, :avatar
132
- end
133
- ```
134
-
135
-
136
60
  ### Include assets
137
61
 
138
62
  Javascripts:
@@ -156,19 +80,19 @@ Stylesheets:
156
80
  or FormBuilder:
157
81
 
158
82
  ```erb
159
- <%= form.uploader_field :photo, :sortable => true %>
83
+ <%= form.uploader_field :photo, sortable: true %>
160
84
  ```
161
85
 
162
86
  ### Formtastic
163
87
 
164
88
  ```erb
165
- <%= f.input :pictures, :as => :uploader %>
89
+ <%= f.input :pictures, as: :uploader %>
166
90
  ```
167
91
 
168
92
  ### SimpleForm
169
93
 
170
94
  ```erb
171
- <%= f.input :pictures, :as => :uploader, :input_html => {:sortable => true} %>
95
+ <%= f.input :pictures, as: :uploader, input_html: { sortable: true } %>
172
96
  ```
173
97
 
174
98
  #### Confirming deletions
@@ -181,6 +105,158 @@ This is only working in Formtastic and FormBuilder:
181
105
  # the i18n lookup key would be en.formtastic.delete_confirmations.picture
182
106
  ```
183
107
 
108
+ ## Authorization
109
+
110
+ Setup custom authorization adapter and current user:
111
+
112
+ ``` ruby
113
+ # config/initializers/uploader.rb
114
+ Uploader.setup do |config|
115
+ config.authorization_adapter = CanCanUploaderAdapter
116
+ config.current_user_proc = -> (request) { request.env['warden'].user }
117
+ end
118
+ ```
119
+
120
+ CanCanUploaderAdapter class just create cancan ability object and call can? method with same args:
121
+
122
+ ``` ruby
123
+ class CanCanUploaderAdapter < Uploader::AuthorizationAdapter
124
+ def authorized?(action, subject = nil)
125
+ cancan_ability.can?(action, subject)
126
+ end
127
+
128
+ def scope_collection(collection, action = :index)
129
+ collection.accessible_by(cancan_ability, action)
130
+ end
131
+
132
+ protected
133
+
134
+ def cancan_ability
135
+ @cancan_ability ||= Ability.new(user)
136
+ end
137
+ end
138
+ ```
139
+
140
+ ## JSON Response
141
+
142
+ https://github.com/blueimp/jQuery-File-Upload/wiki/Setup#using-jquery-file-upload-ui-version-with-a-custom-server-side-upload-handler
143
+
144
+ Extend your custom server-side upload handler to return a JSON response akin to the following output:
145
+
146
+ ``` json
147
+ {"files": [
148
+ {
149
+ "name": "picture1.jpg",
150
+ "size": 902604,
151
+ "url": "http:\/\/example.org\/files\/picture1.jpg",
152
+ "thumb_url": "http:\/\/example.org\/files\/thumbnail\/picture1.jpg",
153
+ "id": 1,
154
+ "content_type": "image/jpg"
155
+ },
156
+ {
157
+ "name": "picture2.jpg",
158
+ "size": 841946,
159
+ "url": "http:\/\/example.org\/files\/picture2.jpg",
160
+ "thumb_url": "http:\/\/example.org\/files\/thumbnail\/picture2.jpg",
161
+ "id": 2,
162
+ "content_type": "image/jpg"
163
+ }
164
+ ]}
165
+ ```
166
+
167
+ To return errors to the UI, just add an error property to the individual file objects:
168
+
169
+ ``` json
170
+ {"files": [
171
+ {
172
+ "name": "picture1.jpg",
173
+ "size": 902604,
174
+ "error": "Filetype not allowed"
175
+ },
176
+ {
177
+ "name": "picture2.jpg",
178
+ "size": 841946,
179
+ "error": "Filetype not allowed"
180
+ }
181
+ ]}
182
+ ```
183
+
184
+ When removing files using the delete button, the response should be like this:
185
+
186
+ ``` json
187
+ {"files": [
188
+ {
189
+ "picture1.jpg": true
190
+ },
191
+ {
192
+ "picture2.jpg": true
193
+ }
194
+ ]}
195
+ ```
196
+
197
+ Note that the response should always be a JSON object containing a files array even if only one file is uploaded.
198
+
199
+ ### Customize JSON response and views
200
+
201
+ To customize JSON response just overwrite to_fileupload method:
202
+
203
+ ``` ruby
204
+ class Asset
205
+ include Uploader::Asset
206
+
207
+ def to_fileupload
208
+ {
209
+ id: id,
210
+ name: filename,
211
+ content_type: content_type,
212
+ size: size,
213
+ url: url,
214
+ thumb_url: thumb_url
215
+ }
216
+ end
217
+ end
218
+ ```
219
+
220
+ For exsample let's overwrite id method to public_token method:
221
+
222
+ ``` ruby
223
+ class Asset
224
+ include Uploader::Asset
225
+
226
+ def to_fileupload
227
+ super.merge(id: public_token)
228
+ end
229
+
230
+ def self.fileupload_find_asset(params)
231
+ where(public_token: params[:id]).first
232
+ end
233
+ end
234
+ ```
235
+
236
+ To customize views just create new theme. For example create avatar theme:
237
+
238
+ app/views/uploader/avatar/_container.html.erb
239
+ app/views/uploader/avatar/_download.html.erb
240
+ app/views/uploader/avatar/_upload.html.erb
241
+
242
+ And pass theme to input field:
243
+
244
+ ``` slim
245
+ = form.uploader_field :photo, theme: 'avatar'
246
+ ```
247
+
248
+ ## Chunked file uploads
249
+
250
+ Chunked file uploads are only supported by browsers with support for XHR file uploads and the Blob API, which includes Google Chrome and Mozilla Firefox 4+.
251
+
252
+ To upload large files in smaller chunks, set the max_chunk_size option to a preferred maximum chunk size in Bytes:
253
+
254
+ ``` slim
255
+ = f.uploader_field :video, class: 'button', theme: 'media', data: { max_chunk_size: 10_000_000 }
256
+ ```
257
+
258
+ That's it!
259
+
184
260
  ## Contributing
185
261
 
186
262
  1. Fork it
@@ -189,4 +265,4 @@ This is only working in Formtastic and FormBuilder:
189
265
  4. Push to the branch (`git push origin my-new-feature`)
190
266
  5. Create new Pull Request
191
267
 
192
- Copyright (c) 2013 Fodojo, released under the MIT license
268
+ Copyright (c) 2016 Fodojo LLC, released under the MIT license
@@ -1,8 +1,10 @@
1
- //= require uploader/jquery.ui.widget
2
- //= require uploader/locales/en
3
- //= require uploader/tmpl.min
4
- //= require uploader/load-image.min
1
+ //= require uploader/vendor/jquery.ui.widget
2
+ //= require uploader/vendor/tmpl.min
3
+
5
4
  //= require uploader/jquery.iframe-transport
6
5
  //= require uploader/jquery.fileupload
6
+ //= require uploader/jquery.fileupload-process
7
+ //= require uploader/jquery.fileupload-validate
7
8
  //= require uploader/jquery.fileupload-ui
8
9
 
10
+ //= require uploader/jquery.uploader
@@ -0,0 +1,58 @@
1
+ $ = jQuery
2
+
3
+ $.fn.uploaderWidget = (options = {}) ->
4
+ @each ->
5
+ $this = $(this)
6
+ data = $this.data('uploaderWidget')
7
+ if (!data)
8
+ $this.data('uploaderWidget', new UploaderWidget(this, options))
9
+ if (typeof options is 'string')
10
+ data[options]()
11
+
12
+ class UploaderWidget
13
+ constructor: (@dom_id, options = {}) ->
14
+ defaults =
15
+ dataType: 'json'
16
+ autoUpload: true
17
+ paramName: 'asset[data]'
18
+ formData: (form) -> return []
19
+ namespace: 'uploader'
20
+ uploadTemplateId: 'template-upload-'
21
+ downloadTemplateId: 'template-download-'
22
+
23
+ @options = $.extend defaults, options
24
+
25
+ this._setup()
26
+
27
+ _setup: ->
28
+ @element = $(@dom_id)
29
+ @container = @element.find('div.uploader-files')
30
+ @template = @element.data('tpml')
31
+ @input = @element.find('input[type="file"]:eq(0)')
32
+
33
+ @options['dropZone'] = @element
34
+ @options['filesContainer'] = @container
35
+ @options['uploadTemplateId'] += @template
36
+ @options['downloadTemplateId'] += @template
37
+
38
+ this._initFileupload()
39
+
40
+ _initFileupload: ->
41
+ @input.fileupload(@options)
42
+
43
+ @uploader = (@input.data('blueimp-fileupload') || @input.data('fileupload'))
44
+
45
+ this._load() if @element.data('exists')
46
+
47
+ _load: ->
48
+ $.ajax(
49
+ url: @input.data('url')
50
+ dataType: 'json'
51
+ method: 'GET'
52
+ success: (data) =>
53
+ if data['files']?
54
+ this.render(data['files'])
55
+ )
56
+
57
+ render: (files) ->
58
+ @uploader._renderDownload(files).appendTo(@container)
@@ -1,56 +1,80 @@
1
1
  module Uploader
2
2
  class AttachmentsController < ActionController::Metal
3
3
  include AbstractController::Callbacks
4
-
5
- before_filter :find_klass
6
- before_filter :find_asset, :only => [:destroy]
7
-
4
+ include Uploader::Authorization
5
+ include Uploader::ChunkedUploads
6
+
7
+ before_action :find_klass
8
+ before_action :build_asset, only: [:create]
9
+ before_action :find_asset, only: [:destroy]
10
+
11
+ def index
12
+ authorize!(:index, @klass)
13
+
14
+ @assets = @klass.fileupload_find_assets(params)
15
+ @assets = uploader_authorization.scope_collection(@assets)
16
+
17
+ render_json(files: @assets.map(&:to_fileupload))
18
+ end
19
+
8
20
  def create
9
- @asset = @klass.new(params[:asset])
10
- @asset.uploader_create(params, request)
21
+ authorize!(:create, @asset)
22
+
23
+ with_chunked_upload(asset_params[:data]) do |file|
24
+ @asset.data = file
25
+ @asset.fileupload_create(params, request)
26
+ end
27
+
11
28
  render_resourse(@asset, 201)
12
29
  end
13
-
14
- def update
15
- @assets = Array.wrap(params[:assets] || [])
16
30
 
17
- @assets.each_with_index do |id, index|
18
- @klass.where(:id => id).update_all(:sort_order => index)
19
- end
31
+ def update
32
+ authorize!(:update, @klass)
20
33
 
21
- render_json(:files => [])
34
+ @klass.fileupload_update_ordering(params)
35
+ render_json(files: [])
22
36
  end
23
37
 
24
38
  def destroy
25
- @asset.uploader_destroy(params, request)
26
- render_resourse(@asset, 200)
39
+ authorize!(:destroy, @asset)
40
+
41
+ @asset.fileupload_destroy(params, request)
42
+ render_resourse(@asset)
27
43
  end
28
-
44
+
29
45
  protected
30
-
31
- def find_klass
32
- @klass = Uploader.constantize(params[:klass])
33
- raise ActionController::RoutingError.new("Class not found #{params[:klass]}") if @klass.nil?
34
- end
35
46
 
36
- def find_asset
37
- @asset = @klass.where(:public_token => params[:id]).first
38
- raise ActionController::RoutingError.new("Asset not found by guid #{params[:id]}") if @asset.nil?
39
- end
40
-
41
- def render_resourse(record, status = 200)
42
- if record.errors.empty?
43
- render_json({:files => [record]}, status)
44
- else
45
- render_json(record.errors, 422)
46
- end
47
- end
48
-
49
- def render_json(hash_or_object, status = 200)
50
- self.status = status
51
- self.content_type = Uploader.content_type(env["HTTP_USER_AGENT"])
52
- self.response_body = hash_or_object.to_json(:root => false)
47
+ def find_klass
48
+ @klass = Uploader.constantize(params[:klass])
49
+ raise ActionController::RoutingError, "Class not found #{params[:klass]}" if @klass.nil?
50
+ end
51
+
52
+ def build_asset
53
+ @asset = @klass.new(asset_params)
54
+ end
55
+
56
+ def find_asset
57
+ @asset = @klass.fileupload_find_asset(params)
58
+ raise ActionController::RoutingError, "Asset not found by #{params[:id]}" if @asset.nil?
59
+ end
60
+
61
+ def render_resourse(record, status = 200)
62
+ if record.errors.empty?
63
+ render_json({ files: [record.to_fileupload] }, status)
64
+ else
65
+ hash = { name: record.filename, error: record.errors.full_messages.first }
66
+ render_json({ files: [hash] }, 422)
53
67
  end
54
-
68
+ end
69
+
70
+ def render_json(hash_or_object, status = 200)
71
+ self.status = status
72
+ self.content_type = request.format
73
+ self.response_body = hash_or_object.to_json(root: false)
74
+ end
75
+
76
+ def asset_params
77
+ ActionController::Parameters.new(params).require(:asset).permit(:data)
78
+ end
55
79
  end
56
80
  end