mm-attach-it 0.1.2
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.
- 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
|