mm-attach-it 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -0
- data/LICENSE +4 -0
- data/README +172 -0
- data/README.rdoc +172 -0
- data/Rakefile +3 -0
- data/lib/attach_it/attach_it.rb +83 -0
- data/lib/attach_it/attachment_options.rb +169 -0
- data/lib/attach_it/storage/filesystem.rb +30 -0
- data/lib/attach_it/storage/gridfs.rb +34 -0
- data/lib/attach_it/storage/storage.rb +10 -0
- data/lib/attach_it/storage.rb +3 -0
- data/lib/attach_it/version.rb +3 -0
- data/lib/mm-attach-it.rb +5 -0
- data/test/test_helper.rb +134 -0
- data/test/unit/test_attach_it.rb +289 -0
- metadata +164 -0
data/Gemfile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
source "http://rubygems.org"
|
data/LICENSE
ADDED
data/README
ADDED
@@ -0,0 +1,172 @@
|
|
1
|
+
= Mm-attach-it
|
2
|
+
|
3
|
+
Attach files (images, videos, pdfs, txts, zips and etc) to a MongoMapper record. You can choose if you to store it on file system or GridFS.
|
4
|
+
|
5
|
+
== Install
|
6
|
+
|
7
|
+
sudo gem install mm-attach-it
|
8
|
+
|
9
|
+
== Usage
|
10
|
+
|
11
|
+
=== Model
|
12
|
+
|
13
|
+
Declare the plugin and use the attachment method to make attachments.
|
14
|
+
|
15
|
+
class Foo
|
16
|
+
include MongoMapper::Document
|
17
|
+
plugin AttachIt
|
18
|
+
|
19
|
+
has_attachment :photo
|
20
|
+
end
|
21
|
+
|
22
|
+
The default storage is the file system, if you want to change for GridFS you should do:
|
23
|
+
|
24
|
+
class Bar
|
25
|
+
include MongoMapper::Document
|
26
|
+
plugin AttachIt
|
27
|
+
|
28
|
+
has_attachment :photo, { :storage => 'gridfs' }
|
29
|
+
end
|
30
|
+
|
31
|
+
If you want to resize the images (you can store resized images on both: file system or GridFS)
|
32
|
+
|
33
|
+
class Foo
|
34
|
+
include MongoMapper::Document
|
35
|
+
plugin AttachIt
|
36
|
+
|
37
|
+
has_attachment :photo, { :styles => { :small => '100x100>', :medium => '200x200>' } }
|
38
|
+
end
|
39
|
+
|
40
|
+
If you want to validate the attached file (again you can validate attaches on both: file system or GridFS)
|
41
|
+
|
42
|
+
class Foo
|
43
|
+
include MongoMapper::Document
|
44
|
+
plugin AttachIt
|
45
|
+
|
46
|
+
has_attch :photo
|
47
|
+
|
48
|
+
validates_attachment_presence :photo
|
49
|
+
validates_attachment_content_type: photo, :content_type => ['image/jpeg', 'image/gif', 'image/png']
|
50
|
+
validates_attachment_size :photo, { :less_than => 1.megabyte, :greater_than => 500.kilobytes }
|
51
|
+
end
|
52
|
+
|
53
|
+
OBS: But remember, you can attach whatever kind of file!
|
54
|
+
|
55
|
+
If you are using the file system to store the files you can specify the storage directory
|
56
|
+
|
57
|
+
class Foo
|
58
|
+
include MongoMapper::Document
|
59
|
+
plugin AttachIt
|
60
|
+
|
61
|
+
has_attachment :photo, { :path => '/:rails_root/public/images/foos/:id/:style/:filename' }
|
62
|
+
end
|
63
|
+
|
64
|
+
OBS: The default directory is '/:rails_root/public/system/:attachment/:id/:style/:filename'
|
65
|
+
|
66
|
+
Where:
|
67
|
+
* :rails_root - is the root directory of your Rails application
|
68
|
+
* :environment - can be "production", "test" or "development"
|
69
|
+
* :class - the name of the class ('foo' the example above)
|
70
|
+
* :attachment - is the name of the column's collection ('photo' the example above)
|
71
|
+
* :id - the "id" of the record on MongoDB
|
72
|
+
* :style - if you specified the styles
|
73
|
+
* :filename - the name of the file
|
74
|
+
* :extension - the extension of the file
|
75
|
+
|
76
|
+
=== View
|
77
|
+
|
78
|
+
Check the model below
|
79
|
+
|
80
|
+
class Foo
|
81
|
+
include MongoMapper::Document
|
82
|
+
plugin AttachIt
|
83
|
+
|
84
|
+
# on file system
|
85
|
+
has_attachment :photo, {
|
86
|
+
:style => { :thumb => '100x100>' },
|
87
|
+
:url => '/assets/groups/:id/:style/:filename',
|
88
|
+
:path => '/:rails_root/public/image/foos/:id/:style/:filename', :storage => 'gridfs',
|
89
|
+
}
|
90
|
+
|
91
|
+
# on GridFS
|
92
|
+
has_attachment :avatar, {
|
93
|
+
:style => { :thumb => '100x100>' },
|
94
|
+
:storage => 'gridfs',
|
95
|
+
}
|
96
|
+
end
|
97
|
+
|
98
|
+
On form you must set the "multipart" option and the field as "file_field":
|
99
|
+
|
100
|
+
<%= form_for(@foo, :html => { :multipart => true }) do |f| %>
|
101
|
+
|
102
|
+
<p>
|
103
|
+
<%= f.label :photo %>
|
104
|
+
<%= f.file_field :photo %>
|
105
|
+
</p>
|
106
|
+
|
107
|
+
<p>
|
108
|
+
<%= f.label :avatar %>
|
109
|
+
<%= f.file_field :avatar %>
|
110
|
+
</p>
|
111
|
+
|
112
|
+
<div class="actions">
|
113
|
+
<%= f.submit %>
|
114
|
+
</div>
|
115
|
+
<% end %>
|
116
|
+
|
117
|
+
|
118
|
+
The safest way to show the images is using Base64, doesn't matter if you are using the file system or GridFS.
|
119
|
+
|
120
|
+
<img src="<%= foo.photo.base64 %>">
|
121
|
+
<img src="<%= foo.photo.base64('thumb') %>">
|
122
|
+
|
123
|
+
<img src="<%= foo.avatar.base64 %>">
|
124
|
+
<img src="<%= foo.avatar.base64('thumb') %>">
|
125
|
+
|
126
|
+
Also, only for file system, if you specify the 'url' option you can do:
|
127
|
+
|
128
|
+
<%= image_tag foo.photo.url %>
|
129
|
+
<%= image_tag foo.photo.url('thumb') %>
|
130
|
+
|
131
|
+
=== Controller
|
132
|
+
|
133
|
+
If you are using the GridFS to store your files and youn don't want to use Base64 data to show the images you've got to create a action on a controller.
|
134
|
+
|
135
|
+
But first create a new route on the route's file:
|
136
|
+
|
137
|
+
match '/foos/avatar/:id(/:style)', :to => 'foos#avatar'
|
138
|
+
|
139
|
+
Now the controller:
|
140
|
+
|
141
|
+
class FoosController < ApplicationController
|
142
|
+
|
143
|
+
...
|
144
|
+
|
145
|
+
def avatar
|
146
|
+
foo = Foo.where('_id' => BSON::ObjectId(params[:id])).first
|
147
|
+
grid_io_data = (params[:style].nil?) ? foo.avatar.get_from_gridfs : foo.avatar.get_from_gridfs(params[:style])
|
148
|
+
bytes = grid_io_data.read
|
149
|
+
send_data(bytes, :type => foo.avatar_content_type, :disposition => 'inline')
|
150
|
+
end
|
151
|
+
|
152
|
+
...
|
153
|
+
|
154
|
+
end
|
155
|
+
|
156
|
+
And the view do that:
|
157
|
+
|
158
|
+
<%= image_tag "/foos/avatar/#{foo.id.to_s}/small" %>
|
159
|
+
|
160
|
+
== Note on Patches/Pull Requests
|
161
|
+
|
162
|
+
* Fork the project.
|
163
|
+
* Make your feature addition or bug fix.
|
164
|
+
* Add tests for it. This is important so I don't break it in a
|
165
|
+
future version unintentionally.
|
166
|
+
* Commit, do not mess with rakefile, version, or history.
|
167
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
168
|
+
* Send me a pull request. Bonus points for topic branches.
|
169
|
+
|
170
|
+
== Copyright
|
171
|
+
|
172
|
+
Copyright (c) 2010 Adilson Chacon. See LICENSE for details.
|
data/README.rdoc
ADDED
@@ -0,0 +1,172 @@
|
|
1
|
+
= Mm-attach-it
|
2
|
+
|
3
|
+
Attach files (images, videos, pdfs, txts, zips and etc) to a MongoMapper record. You can choose if you to store it on file system or GridFS.
|
4
|
+
|
5
|
+
== Install
|
6
|
+
|
7
|
+
sudo gem install mm-attach-it
|
8
|
+
|
9
|
+
== Usage
|
10
|
+
|
11
|
+
=== Model
|
12
|
+
|
13
|
+
Declare the plugin and use the attachment method to make attachments.
|
14
|
+
|
15
|
+
class Foo
|
16
|
+
include MongoMapper::Document
|
17
|
+
plugin AttachIt
|
18
|
+
|
19
|
+
has_attachment :photo
|
20
|
+
end
|
21
|
+
|
22
|
+
The default storage is the file system, if you want to change for GridFS you should do:
|
23
|
+
|
24
|
+
class Bar
|
25
|
+
include MongoMapper::Document
|
26
|
+
plugin AttachIt
|
27
|
+
|
28
|
+
has_attachment :photo, { :storage => 'gridfs' }
|
29
|
+
end
|
30
|
+
|
31
|
+
If you want to resize the images (you can store resized images on both: file system or GridFS)
|
32
|
+
|
33
|
+
class Foo
|
34
|
+
include MongoMapper::Document
|
35
|
+
plugin AttachIt
|
36
|
+
|
37
|
+
has_attachment :photo, { :styles => { :small => '100x100>', :medium => '200x200>' } }
|
38
|
+
end
|
39
|
+
|
40
|
+
If you want to validate the attached file (again you can validate attaches on both: file system or GridFS)
|
41
|
+
|
42
|
+
class Foo
|
43
|
+
include MongoMapper::Document
|
44
|
+
plugin AttachIt
|
45
|
+
|
46
|
+
has_attch :photo
|
47
|
+
|
48
|
+
validates_attachment_presence :photo
|
49
|
+
validates_attachment_content_type: photo, :content_type => ['image/jpeg', 'image/gif', 'image/png']
|
50
|
+
validates_attachment_size :photo, { :less_than => 1.megabyte, :greater_than => 500.kilobytes }
|
51
|
+
end
|
52
|
+
|
53
|
+
OBS: But remember, you can attach whatever kind of file!
|
54
|
+
|
55
|
+
If you are using the file system to store the files you can specify the storage directory
|
56
|
+
|
57
|
+
class Foo
|
58
|
+
include MongoMapper::Document
|
59
|
+
plugin AttachIt
|
60
|
+
|
61
|
+
has_attachment :photo, { :path => '/:rails_root/public/images/foos/:id/:style/:filename' }
|
62
|
+
end
|
63
|
+
|
64
|
+
OBS: The default directory is '/:rails_root/public/system/:attachment/:id/:style/:filename'
|
65
|
+
|
66
|
+
Where:
|
67
|
+
* :rails_root - is the root directory of your Rails application
|
68
|
+
* :environment - can be "production", "test" or "development"
|
69
|
+
* :class - the name of the class ('foo' the example above)
|
70
|
+
* :attachment - is the name of the column's collection ('photo' the example above)
|
71
|
+
* :id - the "id" of the record on MongoDB
|
72
|
+
* :style - if you specified the styles
|
73
|
+
* :filename - the name of the file
|
74
|
+
* :extension - the extension of the file
|
75
|
+
|
76
|
+
=== View
|
77
|
+
|
78
|
+
Check the model below
|
79
|
+
|
80
|
+
class Foo
|
81
|
+
include MongoMapper::Document
|
82
|
+
plugin AttachIt
|
83
|
+
|
84
|
+
# on file system
|
85
|
+
has_attachment :photo, {
|
86
|
+
:style => { :thumb => '100x100>' },
|
87
|
+
:url => '/assets/groups/:id/:style/:filename',
|
88
|
+
:path => '/:rails_root/public/image/foos/:id/:style/:filename', :storage => 'gridfs',
|
89
|
+
}
|
90
|
+
|
91
|
+
# on GridFS
|
92
|
+
has_attachment :avatar, {
|
93
|
+
:style => { :thumb => '100x100>' },
|
94
|
+
:storage => 'gridfs',
|
95
|
+
}
|
96
|
+
end
|
97
|
+
|
98
|
+
On form you must set the "multipart" option and the field as "file_field":
|
99
|
+
|
100
|
+
<%= form_for(@foo, :html => { :multipart => true }) do |f| %>
|
101
|
+
|
102
|
+
<p>
|
103
|
+
<%= f.label :photo %>
|
104
|
+
<%= f.file_field :photo %>
|
105
|
+
</p>
|
106
|
+
|
107
|
+
<p>
|
108
|
+
<%= f.label :avatar %>
|
109
|
+
<%= f.file_field :avatar %>
|
110
|
+
</p>
|
111
|
+
|
112
|
+
<div class="actions">
|
113
|
+
<%= f.submit %>
|
114
|
+
</div>
|
115
|
+
<% end %>
|
116
|
+
|
117
|
+
|
118
|
+
The safest way to show the images is using Base64, doesn't matter if you are using the file system or GridFS.
|
119
|
+
|
120
|
+
<img src="<%= foo.photo.base64 %>">
|
121
|
+
<img src="<%= foo.photo.base64('thumb') %>">
|
122
|
+
|
123
|
+
<img src="<%= foo.avatar.base64 %>">
|
124
|
+
<img src="<%= foo.avatar.base64('thumb') %>">
|
125
|
+
|
126
|
+
Also, only for file system, if you specify the 'url' option you can do:
|
127
|
+
|
128
|
+
<%= image_tag foo.photo.url %>
|
129
|
+
<%= image_tag foo.photo.url('thumb') %>
|
130
|
+
|
131
|
+
=== Controller
|
132
|
+
|
133
|
+
If you are using the GridFS to store your files and youn don't want to use Base64 data to show the images you've got to create a action on a controller.
|
134
|
+
|
135
|
+
But first create a new route on the route's file:
|
136
|
+
|
137
|
+
match '/foos/avatar/:id(/:style)', :to => 'foos#avatar'
|
138
|
+
|
139
|
+
Now the controller:
|
140
|
+
|
141
|
+
class FoosController < ApplicationController
|
142
|
+
|
143
|
+
...
|
144
|
+
|
145
|
+
def avatar
|
146
|
+
foo = Foo.where('_id' => BSON::ObjectId(params[:id])).first
|
147
|
+
grid_io_data = (params[:style].nil?) ? foo.avatar.get_from_gridfs : foo.avatar.get_from_gridfs(params[:style])
|
148
|
+
bytes = grid_io_data.read
|
149
|
+
send_data(bytes, :type => foo.avatar_content_type, :disposition => 'inline')
|
150
|
+
end
|
151
|
+
|
152
|
+
...
|
153
|
+
|
154
|
+
end
|
155
|
+
|
156
|
+
And the view do that:
|
157
|
+
|
158
|
+
<%= image_tag "/foos/avatar/#{foo.id.to_s}/small" %>
|
159
|
+
|
160
|
+
== Note on Patches/Pull Requests
|
161
|
+
|
162
|
+
* Fork the project.
|
163
|
+
* Make your feature addition or bug fix.
|
164
|
+
* Add tests for it. This is important so I don't break it in a
|
165
|
+
future version unintentionally.
|
166
|
+
* Commit, do not mess with rakefile, version, or history.
|
167
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
168
|
+
* Send me a pull request. Bonus points for topic branches.
|
169
|
+
|
170
|
+
== Copyright
|
171
|
+
|
172
|
+
Copyright (c) 2010 Adilson Chacon. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
module AttachIt
|
2
|
+
|
3
|
+
def self.configure(model)
|
4
|
+
model.class_eval do
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def has_attachment(name, options = {})
|
10
|
+
options.symbolize_keys!
|
11
|
+
name = name.to_sym
|
12
|
+
|
13
|
+
after_save :save_attachments
|
14
|
+
before_destroy :destroy_attachments
|
15
|
+
|
16
|
+
key :"#{name}_file_name", String
|
17
|
+
key :"#{name}_file_size", Integer
|
18
|
+
key :"#{name}_content_type", String
|
19
|
+
key :"#{name}_updated_at", Date
|
20
|
+
|
21
|
+
define_method("#{name}=") do |file|
|
22
|
+
information_for(name, options).assign(file)
|
23
|
+
end
|
24
|
+
|
25
|
+
define_method("#{name}") do
|
26
|
+
information_for(name, options)
|
27
|
+
end
|
28
|
+
|
29
|
+
validates_each name, :logic => lambda { information_for(name, options).send(:flush_errors) }
|
30
|
+
end
|
31
|
+
|
32
|
+
def validates_attachment_size(name = nil, options = {})
|
33
|
+
min = options[:greater_than] || (options[:in] && options[:in].first) || 0
|
34
|
+
max = options[:less_than] || (options[:in] && options[:in].last) || (1.0/0)
|
35
|
+
range = (min..max)
|
36
|
+
message = options[:message] || "file size must be between :min and :max bytes"
|
37
|
+
message = message.gsub(/:min/, min.to_s).gsub(/:max/, max.to_s)
|
38
|
+
|
39
|
+
validates_inclusion_of :"#{name}_file_size",
|
40
|
+
:within => range,
|
41
|
+
:message => message,
|
42
|
+
:allow_nil => true
|
43
|
+
end
|
44
|
+
|
45
|
+
def validates_attachment_presence(name = nil, options = {})
|
46
|
+
message = options[:message] || "must be set"
|
47
|
+
validates_presence_of :"#{name}_file_name",
|
48
|
+
:message => message,
|
49
|
+
:if => options[:if]
|
50
|
+
end
|
51
|
+
|
52
|
+
def validates_attachment_content_type(name = nil, options = {})
|
53
|
+
validation_options = options.dup
|
54
|
+
allowed_types = [validation_options[:content_type]].flatten
|
55
|
+
message = options[:message] || "is not one of #{allowed_types.join(", ")}"
|
56
|
+
|
57
|
+
validates_inclusion_of :"#{name}_content_type",
|
58
|
+
:within => allowed_types,
|
59
|
+
:message => message,
|
60
|
+
:allow_nil => true
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
module InstanceMethods
|
65
|
+
def information_for(name = nil, options = nil)
|
66
|
+
@attachment_options ||= {}
|
67
|
+
@attachment_options[name] ||= AttachmentOptions.new(self, name, options)
|
68
|
+
end
|
69
|
+
|
70
|
+
def save_attachments
|
71
|
+
@attachment_options.keys.each do |name|
|
72
|
+
@attachment_options[name].save
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def destroy_attachments
|
77
|
+
@attachment_options.keys.each do |name|
|
78
|
+
@attachment_options[name].delete
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
require 'wand'
|
2
|
+
|
3
|
+
class AttachmentOptions
|
4
|
+
|
5
|
+
attr_accessor :styles, :assigned_file, :object_id, :name
|
6
|
+
|
7
|
+
def initialize(model = nil, name = nil, options = {})
|
8
|
+
@model = model
|
9
|
+
@class_name = model.class.name.downcase
|
10
|
+
@object_id = model.id.to_s
|
11
|
+
|
12
|
+
@name = name
|
13
|
+
@attachment = name.to_s.downcase.pluralize
|
14
|
+
|
15
|
+
@url = set_url(options[:url], options[:default_url])
|
16
|
+
@path = set_path(options[:path])
|
17
|
+
@styles = set_styles(options[:styles])
|
18
|
+
@storage = set_storage(options[:storage])
|
19
|
+
|
20
|
+
if !@model.send("#{@name.to_s}_file_name").nil?
|
21
|
+
@filename = @model.send("#{@name.to_s}_file_name")
|
22
|
+
@extension = set_extension(@model.send("#{@name.to_s}_file_name"))
|
23
|
+
end
|
24
|
+
|
25
|
+
@queued_for_delete = set_queued_for_delete
|
26
|
+
|
27
|
+
@errors = Hash.new
|
28
|
+
end
|
29
|
+
|
30
|
+
def assign(file = nil)
|
31
|
+
@errors = {}
|
32
|
+
|
33
|
+
@filename = file_name(file)
|
34
|
+
@extension = set_extension(@filename)
|
35
|
+
file = file.tempfile if file.respond_to?(:tempfile)
|
36
|
+
|
37
|
+
@model.send("#{@name.to_s}_file_name=", @filename)
|
38
|
+
@model.send("#{@name.to_s}_file_size=", File.size(file))
|
39
|
+
@model.send("#{@name.to_s}_content_type=", Wand.wave(file.path))
|
40
|
+
@model.send("#{@name.to_s}_updated_at=", Time.now)
|
41
|
+
|
42
|
+
add_error('Could not resize file') unless file_is_resizale?
|
43
|
+
end
|
44
|
+
|
45
|
+
def url(style_name = 'original')
|
46
|
+
return nil unless @storage.is_a?(Filesystem)
|
47
|
+
interpolate(@url, style_name)
|
48
|
+
end
|
49
|
+
|
50
|
+
def path(style_name = 'original')
|
51
|
+
return nil unless @storage.is_a?(Filesystem)
|
52
|
+
interpolate(@path, style_name)
|
53
|
+
end
|
54
|
+
|
55
|
+
def save
|
56
|
+
unless @assigned_file.nil?
|
57
|
+
@storage.flush_delete(@queued_for_delete)
|
58
|
+
@storage.flush_write(self)
|
59
|
+
@queued_for_delete = set_queued_for_delete
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def delete
|
64
|
+
@storage.flush_delete(@queued_for_delete)
|
65
|
+
end
|
66
|
+
|
67
|
+
def add_error(description = nil)
|
68
|
+
(@errors[:processing] ||= []) << description
|
69
|
+
end
|
70
|
+
|
71
|
+
def flush_errors
|
72
|
+
@errors.each do |error, message|
|
73
|
+
[message].flatten.each { |m| @model.errors.add(@name, m) }
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def file_name(file = nil)
|
78
|
+
@assigned_file ||= file
|
79
|
+
@assigned_file.respond_to?(:original_filename) ? @assigned_file.original_filename : File.basename(@assigned_file.path)
|
80
|
+
end
|
81
|
+
|
82
|
+
def get_from_gridfs(style = 'original')
|
83
|
+
if @storage.is_a?(Gridfs)
|
84
|
+
@storage.read("#{@object_id}_#{@name}_#{style}")
|
85
|
+
else
|
86
|
+
nil
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def base64(style = 'original')
|
91
|
+
begin
|
92
|
+
bytes = nil
|
93
|
+
|
94
|
+
if @storage.is_a?(Gridfs)
|
95
|
+
bytes = get_from_gridfs(style).read
|
96
|
+
elsif @storage.is_a?(Filesystem)
|
97
|
+
bytes = File.open(path(style), 'rb').read
|
98
|
+
end
|
99
|
+
|
100
|
+
'data:' + @model.send("#{@name.to_s}_content_type") + ';base64,' + Base64.encode64(bytes)
|
101
|
+
rescue Exception => exception
|
102
|
+
nil
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
def interpolate(source = nil, style_name = nil)
|
108
|
+
result = source.gsub(/\:rails_root/, Rails.root)
|
109
|
+
result.gsub!(/\:environment/, Rails.env)
|
110
|
+
result.gsub!(/\:filename/, @filename.nil? ? '' : @filename)
|
111
|
+
result.gsub!(/\:extension/, @extension.nil? ? '' : @extension)
|
112
|
+
result.gsub!(/\:style/, style_name.to_s)
|
113
|
+
result.gsub!(/\:id/, @object_id)
|
114
|
+
result.gsub!(/\:class/, @class_name)
|
115
|
+
result.gsub!(/\:attachment/, @attachment)
|
116
|
+
result.gsub!(/(\/){2,}/, '/')
|
117
|
+
result
|
118
|
+
end
|
119
|
+
|
120
|
+
def set_storage(storage_option = nil)
|
121
|
+
storage_option = 'filesystem' if storage_option.nil?
|
122
|
+
(storage_option == 'filesystem') ? Filesystem.new : Gridfs.new
|
123
|
+
end
|
124
|
+
|
125
|
+
def set_styles(style_option = nil)
|
126
|
+
style_option.nil? ? {} : style_option
|
127
|
+
end
|
128
|
+
|
129
|
+
def set_url(url_option = nil, default_url = nil)
|
130
|
+
@default_url = default_url
|
131
|
+
if url_option.nil?
|
132
|
+
(@default_url.nil? ? '/system/:attachment/:id/:style/:filename' : @default_url)
|
133
|
+
else
|
134
|
+
url_option
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def set_path(path_option = nil)
|
139
|
+
path_option.nil? ? ':rails_root/public/system/:attachment/:id/:style/:filename' : path_option
|
140
|
+
end
|
141
|
+
|
142
|
+
def set_extension(source_path_option = nil)
|
143
|
+
source_path_option.nil? ? nil : File.extname(source_path_option)
|
144
|
+
end
|
145
|
+
|
146
|
+
def set_queued_for_delete
|
147
|
+
if @storage.is_a?(Filesystem)
|
148
|
+
[@styles.keys, :original].flatten.map do |style_name|
|
149
|
+
path(style_name) if File.exists?(path(style_name))
|
150
|
+
end.compact
|
151
|
+
else
|
152
|
+
[@styles.keys, :original].flatten.map do |style_name|
|
153
|
+
"#{@object_id}_#{@name}_#{style_name}"
|
154
|
+
end.compact
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def file_is_resizale?
|
159
|
+
if @styles.keys.size > 0
|
160
|
+
begin
|
161
|
+
system("identify -format %wx%h #{@assigned_file.path}")
|
162
|
+
rescue Exception => exception
|
163
|
+
false
|
164
|
+
end
|
165
|
+
else
|
166
|
+
true
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class Filesystem < Storage
|
2
|
+
|
3
|
+
def flush_write(image_options = nil)
|
4
|
+
image_options.styles.each do |style_name, style_value|
|
5
|
+
begin
|
6
|
+
FileUtils.mkdir_p(File.dirname(image_options.path(style_name)))
|
7
|
+
resize(style_value, image_options.assigned_file.path).write(image_options.path(style_name))
|
8
|
+
FileUtils.chmod(0644, image_options.path(style_name))
|
9
|
+
rescue Exception => exception
|
10
|
+
image_options.add_error(exception.to_s)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
unless image_options.styles.has_key?(:original)
|
15
|
+
begin
|
16
|
+
FileUtils.mkdir_p(File.dirname(image_options.path(:original)))
|
17
|
+
FileUtils.cp(image_options.assigned_file.path, image_options.path(:original))
|
18
|
+
rescue Exception => exception
|
19
|
+
image_options.add_error(exception.to_s)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def flush_delete(queued_for_delete = nil)
|
25
|
+
queued_for_delete.each do |file|
|
26
|
+
FileUtils.rm(file) if File.exist?(file)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class Gridfs < Storage
|
2
|
+
|
3
|
+
def initialize
|
4
|
+
@grid ||= Mongo::Grid.new(MongoMapper.database)
|
5
|
+
end
|
6
|
+
|
7
|
+
def flush_write(image_options = nil)
|
8
|
+
image_options.styles.each do |style_name, style_value|
|
9
|
+
begin
|
10
|
+
gridfs_id = @grid.put(resize(style_value, image_options.assigned_file.path).to_blob, :filename => style_name.to_s + '_' + image_options.file_name, :_id => "#{image_options.object_id}_#{image_options.name}_#{style_name}")
|
11
|
+
rescue Exception => exception
|
12
|
+
image_options.add_error(exception.to_s)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
begin
|
17
|
+
gridfs_id = @grid.put(image_options.assigned_file, :filename => 'original_' + image_options.file_name, :_id => "#{image_options.object_id}_#{image_options.name}_original")
|
18
|
+
rescue Exception => exception
|
19
|
+
image_options.add_error(exception.to_s)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
def flush_delete(queued_for_delete = nil)
|
25
|
+
queued_for_delete.each do |id|
|
26
|
+
@grid.delete(id)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def read(id = nil)
|
31
|
+
@grid.get(id) unless id.nil?
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
data/lib/mm-attach-it.rb
ADDED
@@ -0,0 +1,5 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'attach_it', 'version')
|
2
|
+
require File.join(File.dirname(__FILE__), 'attach_it', 'attach_it')
|
3
|
+
require File.join(File.dirname(__FILE__), 'attach_it', 'attachment_options')
|
4
|
+
require File.join(File.dirname(__FILE__), 'attach_it', 'storage')
|
5
|
+
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'tempfile'
|
3
|
+
require 'mongo_mapper'
|
4
|
+
require 'shoulda'
|
5
|
+
require 'mocha'
|
6
|
+
require File.expand_path(File.dirname(__FILE__) + '/../lib/mm_attach_it')
|
7
|
+
|
8
|
+
MongoMapper.database = "testing_mm_attach_it"
|
9
|
+
|
10
|
+
FakeRailsRoot = File.join(File.dirname(__FILE__) + '/tmp/')
|
11
|
+
|
12
|
+
class Test::Unit::TestCase
|
13
|
+
def setup
|
14
|
+
public_dir = FakeRailsRoot + 'public/'
|
15
|
+
FileUtils.rm_rf(public_dir) if File.exist?(public_dir)
|
16
|
+
FileUtils.mkdir_p(public_dir)
|
17
|
+
MongoMapper.database.collections.each(&:remove)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class UserOne
|
22
|
+
include MongoMapper::Document
|
23
|
+
plugin AttachIt
|
24
|
+
key :name, String
|
25
|
+
has_attachment :avatar
|
26
|
+
end
|
27
|
+
|
28
|
+
class UserTwo
|
29
|
+
include MongoMapper::Document
|
30
|
+
plugin AttachIt
|
31
|
+
key :name, String
|
32
|
+
has_attachment :avatar, { :url => '/assets/users/:id/:filename', :path => ':rails_root/public/assets/users/:id/:filename' }
|
33
|
+
end
|
34
|
+
|
35
|
+
class UserThree
|
36
|
+
include MongoMapper::Document
|
37
|
+
plugin AttachIt
|
38
|
+
key :name, String
|
39
|
+
has_attachment :avatar, { :styles => { :small => '150x150>', :medium => '300x300>' } }
|
40
|
+
end
|
41
|
+
|
42
|
+
class UserFour
|
43
|
+
include MongoMapper::Document
|
44
|
+
plugin AttachIt
|
45
|
+
key :name, String
|
46
|
+
has_attachment :avatar, { :default_url => '/images/default/avatar.jpg' }
|
47
|
+
end
|
48
|
+
|
49
|
+
class UserFive
|
50
|
+
include MongoMapper::Document
|
51
|
+
plugin AttachIt
|
52
|
+
key :name, String
|
53
|
+
has_attachment :avatar
|
54
|
+
|
55
|
+
validates_attachment_size :avatar, :less_than => 1.megabyte
|
56
|
+
end
|
57
|
+
|
58
|
+
class UserSix
|
59
|
+
include MongoMapper::Document
|
60
|
+
plugin AttachIt
|
61
|
+
key :name, String
|
62
|
+
has_attachment :avatar
|
63
|
+
|
64
|
+
validates_attachment_size :avatar, :less_than => 90.kilobytes
|
65
|
+
end
|
66
|
+
|
67
|
+
class UserSeven
|
68
|
+
include MongoMapper::Document
|
69
|
+
plugin AttachIt
|
70
|
+
key :name, String
|
71
|
+
has_attachment :avatar
|
72
|
+
|
73
|
+
validates_attachment_size :avatar, :greater_than => 90.kilobytes
|
74
|
+
end
|
75
|
+
|
76
|
+
class UserEight
|
77
|
+
include MongoMapper::Document
|
78
|
+
plugin AttachIt
|
79
|
+
key :name, String
|
80
|
+
has_attachment :avatar
|
81
|
+
|
82
|
+
validates_attachment_size :avatar, :greater_than => 1.megabyte
|
83
|
+
end
|
84
|
+
|
85
|
+
class UserNine
|
86
|
+
include MongoMapper::Document
|
87
|
+
plugin AttachIt
|
88
|
+
key :name, String
|
89
|
+
has_attachment :avatar
|
90
|
+
|
91
|
+
validates_attachment_presence :avatar
|
92
|
+
end
|
93
|
+
|
94
|
+
class UserTen
|
95
|
+
include MongoMapper::Document
|
96
|
+
plugin AttachIt
|
97
|
+
key :name, String
|
98
|
+
has_attachment :avatar
|
99
|
+
|
100
|
+
validates_attachment_content_type :avatar, :content_type => ['image/gif', 'image/png']
|
101
|
+
end
|
102
|
+
|
103
|
+
class UserEleven
|
104
|
+
include MongoMapper::Document
|
105
|
+
plugin AttachIt
|
106
|
+
key :name, String
|
107
|
+
has_attachment :avatar
|
108
|
+
|
109
|
+
validates_attachment_content_type :avatar, :content_type => ['image/jpg', 'image/jpeg']
|
110
|
+
end
|
111
|
+
|
112
|
+
class UserTwelve
|
113
|
+
include MongoMapper::Document
|
114
|
+
plugin AttachIt
|
115
|
+
key :name, String
|
116
|
+
has_attachment :avatar, { :styles => { :small => '150x150>', :medium => '300x300>' }, :storage => 'gridfs' }
|
117
|
+
end
|
118
|
+
|
119
|
+
class DocumentOne
|
120
|
+
include MongoMapper::Document
|
121
|
+
plugin AttachIt
|
122
|
+
key :name, String
|
123
|
+
has_attachment :document
|
124
|
+
end
|
125
|
+
|
126
|
+
class Rails
|
127
|
+
def self.env
|
128
|
+
'test'
|
129
|
+
end
|
130
|
+
|
131
|
+
def self.root
|
132
|
+
File.join(File.dirname(__FILE__) + '/tmp/')
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,289 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '../test_helper')
|
2
|
+
|
3
|
+
JpgImageFile = File.join(File.dirname(__FILE__) + '/../fixtures/lake_moraine.jpg')
|
4
|
+
PdfFile = File.join(File.dirname(__FILE__) + '/../fixtures/example.pdf')
|
5
|
+
FakeImageFile = File.join(File.dirname(__FILE__) + '/../fixtures/fakeimage.jpg')
|
6
|
+
|
7
|
+
class TestAttachIt < Test::Unit::TestCase
|
8
|
+
context "#initialize" do
|
9
|
+
setup do
|
10
|
+
@user = UserOne.new
|
11
|
+
@user.name = 'Myname'
|
12
|
+
end
|
13
|
+
|
14
|
+
should "set instance of image_options" do
|
15
|
+
assert_instance_of AttachmentOptions, @user.avatar
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context "Attaching an image on file system" do
|
20
|
+
setup do
|
21
|
+
@user = UserOne.new
|
22
|
+
@user.name = 'Myname'
|
23
|
+
@user.avatar = File.open(JpgImageFile, 'rb')
|
24
|
+
end
|
25
|
+
|
26
|
+
should "respond with path and url methods with default value" do
|
27
|
+
destiny_file = Rails.root + 'public/system/avatars/' + @user.id.to_s + '/original/lake_moraine.jpg'
|
28
|
+
assert_equal(destiny_file, @user.avatar.path)
|
29
|
+
|
30
|
+
destiny_url = '/system/avatars/' + @user.id.to_s + '/original/lake_moraine.jpg'
|
31
|
+
assert_equal(destiny_url, @user.avatar.url)
|
32
|
+
end
|
33
|
+
|
34
|
+
should "create file and informations columns after save" do
|
35
|
+
destiny_file = Rails.root + 'public/system/avatars/' + @user.id.to_s + '/original/lake_moraine.jpg'
|
36
|
+
@user.save
|
37
|
+
assert(File.exist?(destiny_file))
|
38
|
+
assert_equal('lake_moraine.jpg', @user.avatar_file_name)
|
39
|
+
assert_equal('image/jpeg', @user.avatar_content_type)
|
40
|
+
assert_equal(102520, @user.avatar_file_size)
|
41
|
+
assert_instance_of(Date, @user.avatar_updated_at)
|
42
|
+
end
|
43
|
+
|
44
|
+
should "retreive correct informations" do
|
45
|
+
destiny_file = Rails.root + 'public/system/avatars/' + @user.id.to_s + '/original/lake_moraine.jpg'
|
46
|
+
destiny_url = '/system/avatars/' + @user.id.to_s + '/original/lake_moraine.jpg'
|
47
|
+
|
48
|
+
@user.save
|
49
|
+
|
50
|
+
saved_user = UserOne.find(@user.id.to_s)
|
51
|
+
assert_equal(destiny_file, saved_user.avatar.path)
|
52
|
+
assert_equal(destiny_url, saved_user.avatar.url)
|
53
|
+
assert_equal('lake_moraine.jpg', saved_user.avatar_file_name)
|
54
|
+
assert_equal(102520, saved_user.avatar_file_size)
|
55
|
+
assert_equal('image/jpeg', saved_user.avatar_content_type)
|
56
|
+
assert_instance_of(Date, saved_user.avatar_updated_at)
|
57
|
+
assert_equal(@user.avatar_updated_at, saved_user.avatar_updated_at)
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
context "Attaching not an image on file system" do
|
64
|
+
|
65
|
+
end
|
66
|
+
setup do
|
67
|
+
@doc = DocumentOne.new
|
68
|
+
@doc.name = 'Mydocument'
|
69
|
+
@doc.document = File.open(PdfFile, 'rb')
|
70
|
+
end
|
71
|
+
|
72
|
+
should "respond with path and url methods with default value" do
|
73
|
+
destiny_file = Rails.root + 'public/system/documents/' + @doc.id.to_s + '/original/example.pdf'
|
74
|
+
assert_equal(destiny_file, @doc.document.path)
|
75
|
+
|
76
|
+
destiny_url = '/system/documents/' + @doc.id.to_s + '/original/example.pdf'
|
77
|
+
assert_equal(destiny_url, @doc.document.url)
|
78
|
+
end
|
79
|
+
|
80
|
+
should "create file and informations columns after save" do
|
81
|
+
destiny_file = Rails.root + 'public/system/documents/' + @doc.id.to_s + '/original/example.pdf'
|
82
|
+
@doc.save
|
83
|
+
assert(File.exist?(destiny_file))
|
84
|
+
assert_equal('example.pdf', @doc.document_file_name)
|
85
|
+
assert_equal('application/pdf', @doc.document_content_type)
|
86
|
+
assert_equal(9785, @doc.document_file_size)
|
87
|
+
assert_instance_of(Date, @doc.document_updated_at)
|
88
|
+
end
|
89
|
+
|
90
|
+
should "retreive correct informations from db" do
|
91
|
+
destiny_file = Rails.root + 'public/system/documents/' + @doc.id.to_s + '/original/example.pdf'
|
92
|
+
destiny_url = '/system/documents/' + @doc.id.to_s + '/original/example.pdf'
|
93
|
+
|
94
|
+
@doc.save
|
95
|
+
|
96
|
+
saved_doc = DocumentOne.find(@doc.id.to_s)
|
97
|
+
assert_equal(destiny_file, saved_doc.document.path)
|
98
|
+
assert_equal(destiny_url, saved_doc.document.url)
|
99
|
+
assert_equal('example.pdf', saved_doc.document_file_name)
|
100
|
+
assert_equal('application/pdf', saved_doc.document_content_type)
|
101
|
+
assert_equal(9785, saved_doc.document_file_size)
|
102
|
+
assert_instance_of(Date, saved_doc.document_updated_at)
|
103
|
+
assert_equal(@doc.document_updated_at, saved_doc.document_updated_at)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
context "Creating differents sizes from an image" do
|
108
|
+
setup do
|
109
|
+
@user = UserThree.new
|
110
|
+
@user.name = 'Myname'
|
111
|
+
@user.avatar = File.open(JpgImageFile, 'rb')
|
112
|
+
end
|
113
|
+
|
114
|
+
should "respond with path and url methods by styles" do
|
115
|
+
[:small, :medium, :original].each do |style|
|
116
|
+
destiny_file = Rails.root + 'public/system/avatars/' + @user.id.to_s + '/' + style.to_s + '/lake_moraine.jpg'
|
117
|
+
assert_equal(destiny_file, @user.avatar.path(style))
|
118
|
+
|
119
|
+
destiny_url = '/system/avatars/' + @user.id.to_s + '/' + style.to_s + '/lake_moraine.jpg'
|
120
|
+
assert_equal(destiny_url, @user.avatar.url(style))
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
should "create file after save by styles" do
|
125
|
+
@user.save
|
126
|
+
[:small, :medium, :original].each do |style|
|
127
|
+
destiny_file = Rails.root + 'public/system/avatars/' + @user.id.to_s + '/' + style.to_s + '/lake_moraine.jpg'
|
128
|
+
assert(File.exist?(destiny_file))
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
should "return the base64 from file" do
|
133
|
+
@user.save
|
134
|
+
assert_match(/^data:image\/jpeg;base64,/, @user.avatar.base64)
|
135
|
+
assert_match(/^data:image\/jpeg;base64,/, @user.avatar.base64('small'))
|
136
|
+
assert_match(/^data:image\/jpeg;base64,/, @user.avatar.base64('medium'))
|
137
|
+
assert_match(/^data:image\/jpeg;base64,/, @user.avatar.base64('original'))
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
context "Set the url and path" do
|
142
|
+
setup do
|
143
|
+
@user = UserTwo.new
|
144
|
+
@user.name = 'Myname'
|
145
|
+
@user.avatar = File.open(JpgImageFile, 'rb')
|
146
|
+
end
|
147
|
+
|
148
|
+
should "respond with path and url" do
|
149
|
+
destiny_file = Rails.root + 'public/assets/users/' + @user.id.to_s + '/lake_moraine.jpg'
|
150
|
+
assert_equal(destiny_file, @user.avatar.path)
|
151
|
+
|
152
|
+
destiny_url = '/assets/users/' + @user.id.to_s + '/lake_moraine.jpg'
|
153
|
+
assert_equal(destiny_url, @user.avatar.url)
|
154
|
+
end
|
155
|
+
|
156
|
+
should "retreive correct informations from db" do
|
157
|
+
destiny_file = Rails.root + 'public/assets/users/' + @user.id.to_s + '/lake_moraine.jpg'
|
158
|
+
destiny_url = '/assets/users/' + @user.id.to_s + '/lake_moraine.jpg'
|
159
|
+
|
160
|
+
@user.save
|
161
|
+
|
162
|
+
saved_user = UserTwo.find(@user.id.to_s)
|
163
|
+
assert_equal(destiny_file, saved_user.avatar.path)
|
164
|
+
assert_equal(destiny_url, saved_user.avatar.url)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
context "Use default URL" do
|
169
|
+
setup do
|
170
|
+
@user = UserFour.new
|
171
|
+
@user.name = 'Myname'
|
172
|
+
end
|
173
|
+
|
174
|
+
should "retreive correct informations from db" do
|
175
|
+
destiny_url = '/images/default/avatar.jpg'
|
176
|
+
|
177
|
+
@user.save
|
178
|
+
|
179
|
+
saved_user = UserFour.find(@user.id.to_s)
|
180
|
+
assert_equal(destiny_url, saved_user.avatar.url)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
context "Handle errors" do
|
185
|
+
setup do
|
186
|
+
end
|
187
|
+
|
188
|
+
should "have an error if file can't be resized" do
|
189
|
+
user = UserThree.new
|
190
|
+
user.name = 'Myname'
|
191
|
+
user.avatar = File.open(FakeImageFile)
|
192
|
+
user.save
|
193
|
+
|
194
|
+
assert_equal(user.errors.size, 1)
|
195
|
+
assert_equal(user.errors[:avatar].first, 'Could not resize file')
|
196
|
+
end
|
197
|
+
|
198
|
+
should "haven't an error if file size is less than a specific value" do
|
199
|
+
user = UserFive.new
|
200
|
+
user.name = 'Myname'
|
201
|
+
user.avatar = File.open(JpgImageFile, 'rb')
|
202
|
+
user.save
|
203
|
+
|
204
|
+
assert_equal(user.errors.size, 0)
|
205
|
+
end
|
206
|
+
|
207
|
+
should "have an error if file size is not less than a specific value" do
|
208
|
+
user = UserSix.new
|
209
|
+
user.name = 'Myname'
|
210
|
+
user.avatar = File.open(JpgImageFile, 'rb')
|
211
|
+
user.save
|
212
|
+
|
213
|
+
assert_equal(user.errors.size, 1)
|
214
|
+
assert_equal(user.errors[:avatar_file_size].first, 'file size must be between 0 and 92160 bytes')
|
215
|
+
end
|
216
|
+
|
217
|
+
should "haven't error if file size is greater than a specific value" do
|
218
|
+
user = UserSeven.new
|
219
|
+
user.name = 'Myname'
|
220
|
+
user.avatar = File.open(JpgImageFile, 'rb')
|
221
|
+
user.save
|
222
|
+
|
223
|
+
assert_equal(user.errors.size, 0)
|
224
|
+
end
|
225
|
+
|
226
|
+
should "have an error if file size is not greater than a specific value" do
|
227
|
+
user = UserEight.new
|
228
|
+
user.name = 'Myname'
|
229
|
+
user.avatar = File.open(JpgImageFile, 'rb')
|
230
|
+
user.save
|
231
|
+
|
232
|
+
assert_equal(user.errors.size, 1)
|
233
|
+
assert_equal(user.errors[:avatar_file_size].first, 'file size must be between 1048576 and Infinity bytes')
|
234
|
+
end
|
235
|
+
|
236
|
+
should "have an error if file size is not greater than a specific value" do
|
237
|
+
user = UserNine.new
|
238
|
+
user.name = 'Myname'
|
239
|
+
user.save
|
240
|
+
|
241
|
+
assert_equal(user.errors.size, 1)
|
242
|
+
assert_equal(user.errors[:avatar_file_name].first, 'must be set')
|
243
|
+
end
|
244
|
+
|
245
|
+
should "have an error if file content type is not one of the specifieds" do
|
246
|
+
user = UserTen.new
|
247
|
+
user.name = 'Myname'
|
248
|
+
user.avatar = File.open(JpgImageFile, 'rb')
|
249
|
+
user.save
|
250
|
+
|
251
|
+
assert_equal(user.errors.size, 1)
|
252
|
+
assert_equal(user.errors[:avatar_content_type].first, 'is not one of image/gif, image/png')
|
253
|
+
end
|
254
|
+
|
255
|
+
should "haven't error if file content type is one of the specifieds" do
|
256
|
+
user = UserEleven.new
|
257
|
+
user.name = 'Myname'
|
258
|
+
user.avatar = File.open(JpgImageFile, 'rb')
|
259
|
+
user.save
|
260
|
+
|
261
|
+
assert_equal(user.errors.size, 0)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
context "Gridfs behavior" do
|
266
|
+
setup do
|
267
|
+
@user = UserTwelve.new
|
268
|
+
@user.name = 'Myname'
|
269
|
+
@user.avatar = File.open(JpgImageFile, 'rb')
|
270
|
+
@user.save
|
271
|
+
end
|
272
|
+
|
273
|
+
should "save the images resizeds and the original" do
|
274
|
+
assert_equal(@user.avatar.get_from_gridfs.class, Mongo::GridIO)
|
275
|
+
assert_equal(@user.avatar.get_from_gridfs('small').class, Mongo::GridIO)
|
276
|
+
assert_equal(@user.avatar.get_from_gridfs('medium').class, Mongo::GridIO)
|
277
|
+
assert_equal(@user.avatar.get_from_gridfs('original').class, Mongo::GridIO)
|
278
|
+
end
|
279
|
+
|
280
|
+
should "return the base64 from file" do
|
281
|
+
assert_match(/^data:image\/jpeg;base64,/, @user.avatar.base64)
|
282
|
+
assert_match(/^data:image\/jpeg;base64,/, @user.avatar.base64('small'))
|
283
|
+
assert_match(/^data:image\/jpeg;base64,/, @user.avatar.base64('medium'))
|
284
|
+
assert_match(/^data:image\/jpeg;base64,/, @user.avatar.base64('original'))
|
285
|
+
end
|
286
|
+
|
287
|
+
end
|
288
|
+
|
289
|
+
end
|
metadata
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mm-attach-it
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 31
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 2
|
10
|
+
version: 0.1.2
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Adilson Chacon
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-05-30 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: wand
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 3
|
29
|
+
segments:
|
30
|
+
- 0
|
31
|
+
version: "0"
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: mongo_mapper
|
36
|
+
prerelease: false
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
hash: 3
|
43
|
+
segments:
|
44
|
+
- 0
|
45
|
+
version: "0"
|
46
|
+
type: :runtime
|
47
|
+
version_requirements: *id002
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: rmagick
|
50
|
+
prerelease: false
|
51
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
hash: 3
|
57
|
+
segments:
|
58
|
+
- 0
|
59
|
+
version: "0"
|
60
|
+
type: :runtime
|
61
|
+
version_requirements: *id003
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: mime-types
|
64
|
+
prerelease: false
|
65
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
hash: 3
|
71
|
+
segments:
|
72
|
+
- 0
|
73
|
+
version: "0"
|
74
|
+
type: :runtime
|
75
|
+
version_requirements: *id004
|
76
|
+
- !ruby/object:Gem::Dependency
|
77
|
+
name: shoulda
|
78
|
+
prerelease: false
|
79
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
80
|
+
none: false
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
hash: 3
|
85
|
+
segments:
|
86
|
+
- 0
|
87
|
+
version: "0"
|
88
|
+
type: :development
|
89
|
+
version_requirements: *id005
|
90
|
+
- !ruby/object:Gem::Dependency
|
91
|
+
name: mocha
|
92
|
+
prerelease: false
|
93
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
hash: 3
|
99
|
+
segments:
|
100
|
+
- 0
|
101
|
+
version: "0"
|
102
|
+
type: :development
|
103
|
+
version_requirements: *id006
|
104
|
+
description: Attach files (images, videos, pdfs, txts, zips and etc) to a MongoMapper record. You can choose if you to store it on file system or GridFS.
|
105
|
+
email: adilsonchacon@gmail.com
|
106
|
+
executables: []
|
107
|
+
|
108
|
+
extensions: []
|
109
|
+
|
110
|
+
extra_rdoc_files:
|
111
|
+
- README
|
112
|
+
- README.rdoc
|
113
|
+
files:
|
114
|
+
- README
|
115
|
+
- README.rdoc
|
116
|
+
- LICENSE
|
117
|
+
- Rakefile
|
118
|
+
- Gemfile
|
119
|
+
- lib/mm-attach-it.rb
|
120
|
+
- lib/attach_it/version.rb
|
121
|
+
- lib/attach_it/storage/gridfs.rb
|
122
|
+
- lib/attach_it/storage/filesystem.rb
|
123
|
+
- lib/attach_it/storage/storage.rb
|
124
|
+
- lib/attach_it/attachment_options.rb
|
125
|
+
- lib/attach_it/attach_it.rb
|
126
|
+
- lib/attach_it/storage.rb
|
127
|
+
- test/test_helper.rb
|
128
|
+
- test/unit/test_attach_it.rb
|
129
|
+
homepage: https://github.com/adilsonchacon/mm-attach-it
|
130
|
+
licenses: []
|
131
|
+
|
132
|
+
post_install_message:
|
133
|
+
rdoc_options: []
|
134
|
+
|
135
|
+
require_paths:
|
136
|
+
- lib
|
137
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
138
|
+
none: false
|
139
|
+
requirements:
|
140
|
+
- - ">="
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
hash: 3
|
143
|
+
segments:
|
144
|
+
- 0
|
145
|
+
version: "0"
|
146
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
147
|
+
none: false
|
148
|
+
requirements:
|
149
|
+
- - ">="
|
150
|
+
- !ruby/object:Gem::Version
|
151
|
+
hash: 3
|
152
|
+
segments:
|
153
|
+
- 0
|
154
|
+
version: "0"
|
155
|
+
requirements:
|
156
|
+
- ImageMagick
|
157
|
+
rubyforge_project: mm-attach_it
|
158
|
+
rubygems_version: 1.8.4
|
159
|
+
signing_key:
|
160
|
+
specification_version: 3
|
161
|
+
summary: MongoMapper Plugin File Attacher.
|
162
|
+
test_files:
|
163
|
+
- test/unit/test_attach_it.rb
|
164
|
+
- test/test_helper.rb
|