progstr-filer 0.8.1 → 0.8.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +107 -0
- data/VERSION +1 -1
- data/lib/filer/activerecord.rb +0 -6
- data/lib/filer/attachment.rb +5 -1
- data/lib/filer/validation.rb +8 -6
- data/test/adium-green-duckling.png +0 -0
- data/test/test_validation.rb +14 -0
- metadata +34 -33
- data/README.rdoc +0 -19
data/README.md
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
Progstr Filer is a developer-friendly file hosting platform built specifically for web apps. It lets you easily associate file attachments with your ActiveRecord models and removes the hassle of actually hosting the files yourself.
|
2
|
+
|
3
|
+
### Setting up the Ruby gem
|
4
|
+
|
5
|
+
Bundler makes that all too easy - add this line to your `Gemfile` to have the gem pulled into your app and required automatically.
|
6
|
+
|
7
|
+
|
8
|
+
gem "progstr-filer", :require => "progstr-filer"
|
9
|
+
|
10
|
+
|
11
|
+
### Credentials
|
12
|
+
|
13
|
+
Progstr Filer uses two keys similar to Amazon's cloud services. The access key is a public string that gets rendered publicly in URL's and web pages. We use it to identify your account. The secret key is used to sign and encrypt sensitive data. You should keep it, well, secret.
|
14
|
+
|
15
|
+
Provisioning your add-on with Heroku gets you two environment variables: `PROGSTR_FILER_ACCESS_KEY` and `PROGSTR_FILER_SECRET_KEY`. Add those to your `config/environments/production.rb` file:
|
16
|
+
|
17
|
+
Progstr::Filer.access_key = ENV['PROGSTR_FILER_ACCESS_KEY']
|
18
|
+
Progstr::Filer.secret_key = ENV['PROGSTR_FILER_SECRET_KEY']
|
19
|
+
|
20
|
+
|
21
|
+
### Defining an uploader
|
22
|
+
|
23
|
+
Every attachment can have a specific set of options that take effect while uploading and manipulating it. Those settings get configured via your own class that will extend `Progstr::Filer::Uploader`. You could store uploader classes in your `app/uploaders` folder. Here is a sample class:
|
24
|
+
|
25
|
+
class AvatarUploader < Progstr::Filer::Uploader
|
26
|
+
#uploader options
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
### Associating uploaders with your models
|
31
|
+
|
32
|
+
Progstr Filer extends ActiveRecord models and lets you use the `has_file` method in class definitions. Here is a User model class that has an avatar image managed as a Progstr Filer attachment via its `avatar` property:
|
33
|
+
|
34
|
+
class User < ActiveRecord::Base
|
35
|
+
has_file :avatar, AvatarUploader
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
Note: make sure your database table has an `avatar` column created already. Future versions of the `progstr-filer` gem will let you generate migrations automatically.
|
40
|
+
|
41
|
+
### Feeding data to your uploaders
|
42
|
+
|
43
|
+
That is easy - all you need is assign a Ruby File object to the uploader property and save the model object:
|
44
|
+
|
45
|
+
@user.avatar = uploaded_image_file
|
46
|
+
@user.avatar.save
|
47
|
+
|
48
|
+
|
49
|
+
Rails can get most of the job done for you automatically if you create a file upload form:
|
50
|
+
|
51
|
+
<div class="field">
|
52
|
+
<%= f.label :avatar %>
|
53
|
+
<%= f.file_field :avatar %>
|
54
|
+
</div>
|
55
|
+
|
56
|
+
|
57
|
+
...and create your model from the params hash:
|
58
|
+
|
59
|
+
@user = User.new(params[:user])
|
60
|
+
@user.save
|
61
|
+
|
62
|
+
|
63
|
+
### Generating URLs for files
|
64
|
+
|
65
|
+
Just use the `url` method on your attachments, say `@user.avatar.url`. Here is a sample view that generates an `img` tag pointing to the avatar image:
|
66
|
+
|
67
|
+
<p>
|
68
|
+
<b>Avatar:</b><br>
|
69
|
+
<%= image_tag @user.avatar.url, :style => "max-width: 600px; margin: 10px 0px;" %>
|
70
|
+
</p>
|
71
|
+
|
72
|
+
### Validation
|
73
|
+
|
74
|
+
Users may upload all types of files to your application and it might be a good idea to restrict that to the set of files that your application knows how to process. For example it would not be a good idea to allow non-image file types as an avatar picture. It might be a good idea to disable executable content that might spread malware too. To help with that the `progstr-filer` gem currently supports attachment validation according to an extension whitelist through the `validates_file_extension_of` method that is available to model objects:
|
75
|
+
|
76
|
+
class User < ActiveRecord::Base
|
77
|
+
has_file :avatar, AvatarUploader
|
78
|
+
validates_file_extension_of :avatar, :allowed => ["jpg", "png"]
|
79
|
+
end
|
80
|
+
|
81
|
+
In addition you can restrict the file size using `validates_file_size_of`:
|
82
|
+
|
83
|
+
class User < ActiveRecord::Base
|
84
|
+
has_file :avatar, AvatarUploader
|
85
|
+
validates_file_size_of :avatar, :less_than => 1 * 1024 * 1024
|
86
|
+
end
|
87
|
+
|
88
|
+
The example above will not allow files larger than 1 MB. You can specify a lower bound using the `:greater_than` option or even pass a numeric range using the `:in` option.
|
89
|
+
|
90
|
+
Of course, requiring users to always upload a file when saving a model object, use the Rails built-in `validates_presence_of` validator:
|
91
|
+
|
92
|
+
class User < ActiveRecord::Base
|
93
|
+
has_file :avatar, AvatarUploader
|
94
|
+
validates_presence_of :avatar
|
95
|
+
end
|
96
|
+
|
97
|
+
You can pass a custom error message for all validators using the `:message` option.
|
98
|
+
|
99
|
+
### Deleting stale files
|
100
|
+
|
101
|
+
Every time you set a new file and save your model, the old file will get scheduled for deletion. The same happens when you `destroy` your model. Note that calling `delete` for your model will not delete any associated files.
|
102
|
+
|
103
|
+
### Source code
|
104
|
+
|
105
|
+
The `progstr-filer` [gem](https://rubygems.org/gems/progstr-filer) is open source and its code is hosted on [Github](https://github.com/progstr/progstr-filer-gem).
|
106
|
+
|
107
|
+
All the techniques outlined in this document are available as a fully-functional Rails project on [Github](https://github.com/progstr/progstr-filer-demo) too.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.8.
|
1
|
+
0.8.2
|
data/lib/filer/activerecord.rb
CHANGED
@@ -23,12 +23,6 @@ module Progstr
|
|
23
23
|
def #{attribute}=(new_file)
|
24
24
|
_set_attachment(:#{attribute}, new_file)
|
25
25
|
end
|
26
|
-
def #{attribute}_file_size
|
27
|
-
_get_attachment(:#{attribute}).size
|
28
|
-
end
|
29
|
-
def #{attribute}_file_extension
|
30
|
-
_get_attachment(:#{attribute}).extension
|
31
|
-
end
|
32
26
|
def upload_#{attribute}!
|
33
27
|
_upload_attachment(:#{attribute})
|
34
28
|
end
|
data/lib/filer/attachment.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Progstr
|
2
2
|
module Filer
|
3
3
|
class Attachment
|
4
|
-
attr_accessor :id, :attribute, :file
|
4
|
+
attr_accessor :id, :attribute, :file, :pre_validated
|
5
5
|
|
6
6
|
@@id_generator = ::UUID.new
|
7
7
|
|
@@ -31,7 +31,9 @@ module Progstr
|
|
31
31
|
result = Attachment.new
|
32
32
|
result.id = generate_id
|
33
33
|
result.attribute = attribute
|
34
|
+
|
34
35
|
result.file = file
|
36
|
+
result.pre_validated = false
|
35
37
|
result
|
36
38
|
end
|
37
39
|
|
@@ -58,6 +60,8 @@ module Progstr
|
|
58
60
|
result = Attachment.new
|
59
61
|
result.id = id
|
60
62
|
result.attribute = attribute
|
63
|
+
|
64
|
+
result.pre_validated = true
|
61
65
|
result
|
62
66
|
end
|
63
67
|
|
data/lib/filer/validation.rb
CHANGED
@@ -11,7 +11,7 @@ module Progstr
|
|
11
11
|
|
12
12
|
message = options[:message] || "File size not between #{min} and #{max} bytes."
|
13
13
|
|
14
|
-
validates_with
|
14
|
+
validates_with AttachmentPropertyValidator, :attributes => [attribute],
|
15
15
|
:property => :size,
|
16
16
|
:in => allowed_range,
|
17
17
|
:message => message,
|
@@ -23,7 +23,7 @@ module Progstr
|
|
23
23
|
allowed = options[:allowed] || EverythingIncluded.new
|
24
24
|
message = options[:message] || "File extension not allowed."
|
25
25
|
|
26
|
-
validates_with
|
26
|
+
validates_with AttachmentPropertyValidator, :attributes => [attribute],
|
27
27
|
:property => :extension,
|
28
28
|
:in => allowed,
|
29
29
|
:message => message
|
@@ -35,15 +35,17 @@ module Progstr
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
-
class
|
38
|
+
class AttachmentPropertyValidator < ActiveModel::Validations::InclusionValidator
|
39
39
|
def initialize(options)
|
40
40
|
@property = options[:property]
|
41
41
|
super(options)
|
42
42
|
end
|
43
43
|
|
44
|
-
def validate_each(record, attribute,
|
45
|
-
|
46
|
-
|
44
|
+
def validate_each(record, attribute, attachment)
|
45
|
+
unless attachment.pre_validated
|
46
|
+
property_value = attachment.send(@property)
|
47
|
+
super(record, attribute, property_value) unless attachment.nil? || attachment.blank? || property_value.nil?
|
48
|
+
end
|
47
49
|
end
|
48
50
|
end
|
49
51
|
end
|
Binary file
|
data/test/test_validation.rb
CHANGED
@@ -46,6 +46,20 @@ class TestValidation < UserTest
|
|
46
46
|
assert_equal u.errors[:avatar], ["Avatar image extension not allowed."]
|
47
47
|
end
|
48
48
|
|
49
|
+
test "don't validate prevalidated attachments on record update" do
|
50
|
+
u = ValidatedUser.new
|
51
|
+
u.name = "John"
|
52
|
+
avatar = File.open("test/adium-green-duckling.png")
|
53
|
+
u.avatar = avatar
|
54
|
+
save_success = u.save
|
55
|
+
assert_true save_success, "Initially valid."
|
56
|
+
|
57
|
+
loaded = ValidatedUser.find(u.id)
|
58
|
+
loaded.name = "Jim"
|
59
|
+
save_success = loaded.save
|
60
|
+
assert_true save_success, "Still valid on update when attachment not modified."
|
61
|
+
end
|
62
|
+
|
49
63
|
test "validation passes" do
|
50
64
|
u = ValidatedUser.new
|
51
65
|
jpg = FileLike.new
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: progstr-filer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-01-
|
12
|
+
date: 2012-01-12 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
16
|
-
requirement: &
|
16
|
+
requirement: &14664400 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 3.0.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *14664400
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: activemodel
|
27
|
-
requirement: &
|
27
|
+
requirement: &14662460 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: 3.0.0
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *14662460
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: uuid
|
38
|
-
requirement: &
|
38
|
+
requirement: &14658240 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *14658240
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: rest-client
|
49
|
-
requirement: &
|
49
|
+
requirement: &14657280 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *14657280
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: multi_json
|
60
|
-
requirement: &
|
60
|
+
requirement: &14656740 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :runtime
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *14656740
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: sqlite3
|
71
|
-
requirement: &
|
71
|
+
requirement: &14655880 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *14655880
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: guard-test
|
82
|
-
requirement: &
|
82
|
+
requirement: &14655200 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ! '>='
|
@@ -87,10 +87,10 @@ dependencies:
|
|
87
87
|
version: '0'
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *14655200
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: rb-inotify
|
93
|
-
requirement: &
|
93
|
+
requirement: &14654400 !ruby/object:Gem::Requirement
|
94
94
|
none: false
|
95
95
|
requirements:
|
96
96
|
- - ! '>='
|
@@ -98,10 +98,10 @@ dependencies:
|
|
98
98
|
version: '0'
|
99
99
|
type: :development
|
100
100
|
prerelease: false
|
101
|
-
version_requirements: *
|
101
|
+
version_requirements: *14654400
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
103
|
name: libnotify
|
104
|
-
requirement: &
|
104
|
+
requirement: &14653640 !ruby/object:Gem::Requirement
|
105
105
|
none: false
|
106
106
|
requirements:
|
107
107
|
- - ! '>='
|
@@ -109,10 +109,10 @@ dependencies:
|
|
109
109
|
version: '0'
|
110
110
|
type: :development
|
111
111
|
prerelease: false
|
112
|
-
version_requirements: *
|
112
|
+
version_requirements: *14653640
|
113
113
|
- !ruby/object:Gem::Dependency
|
114
114
|
name: shoulda
|
115
|
-
requirement: &
|
115
|
+
requirement: &14652960 !ruby/object:Gem::Requirement
|
116
116
|
none: false
|
117
117
|
requirements:
|
118
118
|
- - ! '>='
|
@@ -120,10 +120,10 @@ dependencies:
|
|
120
120
|
version: '0'
|
121
121
|
type: :development
|
122
122
|
prerelease: false
|
123
|
-
version_requirements: *
|
123
|
+
version_requirements: *14652960
|
124
124
|
- !ruby/object:Gem::Dependency
|
125
125
|
name: bundler
|
126
|
-
requirement: &
|
126
|
+
requirement: &14652280 !ruby/object:Gem::Requirement
|
127
127
|
none: false
|
128
128
|
requirements:
|
129
129
|
- - ~>
|
@@ -131,10 +131,10 @@ dependencies:
|
|
131
131
|
version: 1.0.0
|
132
132
|
type: :development
|
133
133
|
prerelease: false
|
134
|
-
version_requirements: *
|
134
|
+
version_requirements: *14652280
|
135
135
|
- !ruby/object:Gem::Dependency
|
136
136
|
name: jeweler
|
137
|
-
requirement: &
|
137
|
+
requirement: &14648520 !ruby/object:Gem::Requirement
|
138
138
|
none: false
|
139
139
|
requirements:
|
140
140
|
- - ~>
|
@@ -142,10 +142,10 @@ dependencies:
|
|
142
142
|
version: 1.6.4
|
143
143
|
type: :development
|
144
144
|
prerelease: false
|
145
|
-
version_requirements: *
|
145
|
+
version_requirements: *14648520
|
146
146
|
- !ruby/object:Gem::Dependency
|
147
147
|
name: rcov
|
148
|
-
requirement: &
|
148
|
+
requirement: &14647220 !ruby/object:Gem::Requirement
|
149
149
|
none: false
|
150
150
|
requirements:
|
151
151
|
- - ! '>='
|
@@ -153,10 +153,10 @@ dependencies:
|
|
153
153
|
version: '0'
|
154
154
|
type: :development
|
155
155
|
prerelease: false
|
156
|
-
version_requirements: *
|
156
|
+
version_requirements: *14647220
|
157
157
|
- !ruby/object:Gem::Dependency
|
158
158
|
name: rdoc
|
159
|
-
requirement: &
|
159
|
+
requirement: &14646360 !ruby/object:Gem::Requirement
|
160
160
|
none: false
|
161
161
|
requirements:
|
162
162
|
- - ! '>='
|
@@ -164,7 +164,7 @@ dependencies:
|
|
164
164
|
version: '0'
|
165
165
|
type: :development
|
166
166
|
prerelease: false
|
167
|
-
version_requirements: *
|
167
|
+
version_requirements: *14646360
|
168
168
|
description: Progstr Filer is a developer-friendly file and attachment hosting service
|
169
169
|
that lets you easily build apps that store and share files.
|
170
170
|
email: hristo@deshev.com
|
@@ -172,7 +172,7 @@ executables: []
|
|
172
172
|
extensions: []
|
173
173
|
extra_rdoc_files:
|
174
174
|
- LICENSE.txt
|
175
|
-
- README.
|
175
|
+
- README.md
|
176
176
|
files:
|
177
177
|
- .document
|
178
178
|
- .rspec
|
@@ -180,7 +180,7 @@ files:
|
|
180
180
|
- Gemfile.lock
|
181
181
|
- Guardfile
|
182
182
|
- LICENSE.txt
|
183
|
-
- README.
|
183
|
+
- README.md
|
184
184
|
- Rakefile
|
185
185
|
- VERSION
|
186
186
|
- lib/filer/activerecord.rb
|
@@ -190,6 +190,7 @@ files:
|
|
190
190
|
- lib/filer/uploader.rb
|
191
191
|
- lib/filer/validation.rb
|
192
192
|
- lib/progstr-filer.rb
|
193
|
+
- test/adium-green-duckling.png
|
193
194
|
- test/file_like.rb
|
194
195
|
- test/test_attachment_url.rb
|
195
196
|
- test/test_file_mount.rb
|
@@ -214,7 +215,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
214
215
|
version: '0'
|
215
216
|
segments:
|
216
217
|
- 0
|
217
|
-
hash:
|
218
|
+
hash: 4163702518948381072
|
218
219
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
219
220
|
none: false
|
220
221
|
requirements:
|
data/README.rdoc
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
= filer-gem
|
2
|
-
|
3
|
-
Description goes here.
|
4
|
-
|
5
|
-
== Contributing to filer-gem
|
6
|
-
|
7
|
-
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
8
|
-
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
9
|
-
* Fork the project
|
10
|
-
* Start a feature/bugfix branch
|
11
|
-
* Commit and push until you are happy with your contribution
|
12
|
-
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
13
|
-
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
14
|
-
|
15
|
-
== Copyright
|
16
|
-
|
17
|
-
Copyright (c) 2011 Hristo Deshev. See LICENSE.txt for
|
18
|
-
further details.
|
19
|
-
|