attachs 0.3.2 → 0.3.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.rdoc +7 -1
- data/lib/attachs/active_record/base.rb +41 -46
- data/lib/attachs/storages/local.rb +8 -3
- data/lib/attachs/storages/s3.rb +21 -10
- data/lib/attachs/types/file.rb +16 -8
- data/lib/attachs/types/image.rb +27 -9
- data/lib/attachs/validators/attachment_content_type_validator.rb +3 -3
- data/lib/attachs/validators/attachment_presence_validator.rb +2 -2
- data/lib/attachs/validators/attachment_size_validator.rb +2 -8
- data/lib/attachs/validators/base.rb +1 -1
- data/lib/attachs/version.rb +1 -1
- data/lib/tasks/attachs_tasks.rake +4 -3
- data/test/dummy/app/models/all_attached.rb +1 -1
- data/test/dummy/app/models/private_file_attached.rb +3 -0
- data/test/dummy/app/models/private_image_attached.rb +3 -0
- data/test/dummy/config/application.rb +3 -2
- data/test/dummy/config/database.yml +1 -1
- data/test/dummy/log/test.log +3867 -0
- data/test/dummy/tmp/uploads/files/13898788260004868.txt +1 -0
- data/test/local_file_record_test.rb +11 -0
- data/test/test_helper.rb +2 -2
- metadata +9 -7
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/db/test.sqlite3 +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d4b7e169e9f30ad2bf78cb7f234ff71814200ad6
|
4
|
+
data.tar.gz: b8a1b2b599f222bf759809834c9e492389629ef0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2ab3ab663652618fbe9bf500def726a1f101bbb695d7a7bd6ba30b57963fe1b4d2f6b3892d974764b850c53c5f9b0c08b6903acdd782a6e8ad3e258372a27c02
|
7
|
+
data.tar.gz: 45bf708582744d4c012e5b739f921a3c1fc72e4ec2824516dbf9dfa0be08d185956e952f7159f9f25755ca977a343534e3854567be38a598ab8ffaf50e68eb20
|
data/README.rdoc
CHANGED
@@ -18,7 +18,7 @@ ImageMagick must be install, you can install it with homebrew:
|
|
18
18
|
= Usage
|
19
19
|
|
20
20
|
Mount the engine at the end of you routes.rb (only if you are using local storage):
|
21
|
-
mount Attachs
|
21
|
+
mount Attachs::Engine => '/' # Will be use to generate on the fly missing image presets
|
22
22
|
|
23
23
|
Add the column to your table (just a string):
|
24
24
|
create_table :models do |t|
|
@@ -35,6 +35,8 @@ If you need a image:
|
|
35
35
|
has_attached_image :attr, presets: [:small, :big], default: 'assets/image.jpg'
|
36
36
|
end
|
37
37
|
|
38
|
+
(If you want your attachment to be private add private: true to the parameters)
|
39
|
+
|
38
40
|
Define presets in your application.rb
|
39
41
|
config.attachs.presets = {
|
40
42
|
big: { method: :fit, width: 1024, height: 768 }, # Fit will scale the image until it fit in the space without cropping
|
@@ -73,6 +75,10 @@ If your file it's optional:
|
|
73
75
|
|
74
76
|
= FAQ
|
75
77
|
|
78
|
+
== Where my private files are stored?
|
79
|
+
|
80
|
+
In a folder named "private" in the root directory of your app.
|
81
|
+
|
76
82
|
== How can I use a cdn with this plugin?
|
77
83
|
|
78
84
|
Define a base url in your application.rb:
|
@@ -3,20 +3,6 @@ module Attachs
|
|
3
3
|
module Base
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
|
-
included do
|
7
|
-
singleton_class.class_eval do
|
8
|
-
[:file, :image].each do |type|
|
9
|
-
name = :"has_attached_#{type}"
|
10
|
-
define_method name do |*args|
|
11
|
-
options = args.extract_options!
|
12
|
-
options[:type] = type
|
13
|
-
define_attachment *args.append(options)
|
14
|
-
end
|
15
|
-
alias_method :"attached_#{type}", name
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
6
|
protected
|
21
7
|
|
22
8
|
attr_reader :stored_attachments, :deleted_attachments
|
@@ -24,6 +10,22 @@ module Attachs
|
|
24
10
|
def attachments
|
25
11
|
@attachments ||= {}
|
26
12
|
end
|
13
|
+
|
14
|
+
def add_attachment(attr, value, options)
|
15
|
+
attachment = build_attachment_instance(value, options)
|
16
|
+
attachments[attr] = attachment
|
17
|
+
write_attribute attr, attachment.filename
|
18
|
+
end
|
19
|
+
|
20
|
+
def get_attachment(attr, options)
|
21
|
+
return attachments[attr] if attachments.has_key? attr
|
22
|
+
return nil unless read_attribute(attr) or options.has_key? :default
|
23
|
+
attachments[attr] = build_attachment_instance(read_attribute(attr), options)
|
24
|
+
end
|
25
|
+
|
26
|
+
def remove_attachment(attr)
|
27
|
+
write_attribute attr, nil
|
28
|
+
end
|
27
29
|
|
28
30
|
def build_attachment_instance(source, options)
|
29
31
|
klass = options.has_key?(:type) ? options[:type].to_s.classify : 'File'
|
@@ -59,7 +61,7 @@ module Attachs
|
|
59
61
|
end
|
60
62
|
|
61
63
|
def delete_attachments
|
62
|
-
iterate_attachments { |a| a.delete }
|
64
|
+
iterate_attachments { |a| a.delete }
|
63
65
|
end
|
64
66
|
|
65
67
|
def remove_stored_attachments
|
@@ -72,6 +74,16 @@ module Attachs
|
|
72
74
|
|
73
75
|
module ClassMethods
|
74
76
|
|
77
|
+
[:file, :image].each do |type|
|
78
|
+
name = :"has_attached_#{type}"
|
79
|
+
define_method name do |*args|
|
80
|
+
options = args.extract_options!
|
81
|
+
options[:type] = type
|
82
|
+
define_attachment *args.map(&:to_sym).append(options)
|
83
|
+
end
|
84
|
+
alias_method :"attached_#{type}", name
|
85
|
+
end
|
86
|
+
|
75
87
|
attr_reader :attachments
|
76
88
|
|
77
89
|
def inherited(subclass)
|
@@ -89,9 +101,9 @@ module Attachs
|
|
89
101
|
options = args.extract_options!
|
90
102
|
make_attachable unless attachable?
|
91
103
|
args.each do |attr|
|
92
|
-
|
93
|
-
|
94
|
-
attachments[attr
|
104
|
+
define_attachment_attribute_methods attr, options
|
105
|
+
define_attachment_default_validations attr, options
|
106
|
+
attachments[attr] = options
|
95
107
|
end
|
96
108
|
end
|
97
109
|
|
@@ -103,41 +115,24 @@ module Attachs
|
|
103
115
|
@attachments = {}
|
104
116
|
end
|
105
117
|
|
106
|
-
def
|
107
|
-
default_validations = Rails.application.config.attachs.default_validations[options[:type]]
|
108
|
-
validates attr, default_validations.dup if default_validations.present?
|
109
|
-
end
|
110
|
-
|
111
|
-
def define_attachable_attribute_methods(attr, options)
|
112
|
-
['set','get'].each { |method| send "define_attachable_attribute_method_#{method}", attr, options }
|
113
|
-
end
|
114
|
-
|
115
|
-
def define_attachable_attribute_method_set(attr, options)
|
118
|
+
def define_attachment_attribute_methods(attr, options)
|
116
119
|
define_method "#{attr}=" do |value|
|
117
|
-
if value.is_a? ActionDispatch::Http::UploadedFile or value.is_a? Rack::Test::UploadedFile
|
118
|
-
attachment = build_attachment_instance(value, options)
|
119
|
-
attachments[attr] = attachment
|
120
|
-
write_attribute attr, attachment.filename
|
121
|
-
end
|
120
|
+
add_attachment attr, value, options if value.is_a? ActionDispatch::Http::UploadedFile or value.is_a? Rack::Test::UploadedFile
|
122
121
|
end
|
122
|
+
define_method attr do
|
123
|
+
get_attachment attr, options
|
124
|
+
end
|
123
125
|
define_method "delete_#{attr}=" do |value|
|
124
|
-
|
125
|
-
send "#{attr}_will_change!"
|
126
|
-
attachments[attr] = nil
|
127
|
-
attributes[attr.to_s] = nil
|
128
|
-
end
|
126
|
+
remove_attachment attr if value == '1'
|
129
127
|
instance_variable_set :"@delete_#{attr}", value
|
130
128
|
end
|
131
|
-
end
|
132
|
-
|
133
|
-
def define_attachable_attribute_method_get(attr, options)
|
134
|
-
define_method attr do
|
135
|
-
return attachments[attr] if attachments.has_key? attr
|
136
|
-
return nil unless super() or options.has_key? :default
|
137
|
-
attachments[attr] = build_attachment_instance(super(), options)
|
138
|
-
end
|
139
129
|
attr_reader :"delete_#{attr}"
|
140
130
|
end
|
131
|
+
|
132
|
+
def define_attachment_default_validations(attr, options)
|
133
|
+
default_validations = Rails.application.config.attachs.default_validations[options[:type]]
|
134
|
+
validates attr, default_validations.dup if default_validations.present?
|
135
|
+
end
|
141
136
|
|
142
137
|
end
|
143
138
|
end
|
@@ -2,8 +2,9 @@ module Attachs
|
|
2
2
|
module Storages
|
3
3
|
class Local
|
4
4
|
|
5
|
-
def initialize(default)
|
5
|
+
def initialize(default, private)
|
6
6
|
@tmp = (Rails.env.test? and !default)
|
7
|
+
@private = private
|
7
8
|
end
|
8
9
|
|
9
10
|
def exists?(path)
|
@@ -19,7 +20,7 @@ module Attachs
|
|
19
20
|
end
|
20
21
|
|
21
22
|
def url(path)
|
22
|
-
::File.join Rails.application.config.attachs.base_url, path
|
23
|
+
::File.join Rails.application.config.attachs.base_url, path unless private?
|
23
24
|
end
|
24
25
|
|
25
26
|
def store(upload, path)
|
@@ -47,8 +48,12 @@ module Attachs
|
|
47
48
|
@tmp == true
|
48
49
|
end
|
49
50
|
|
51
|
+
def private?
|
52
|
+
@private == true
|
53
|
+
end
|
54
|
+
|
50
55
|
def base_path
|
51
|
-
Rails.root.join tmp? ? 'tmp' : 'public'
|
56
|
+
Rails.root.join tmp? ? 'tmp' : private? ? 'private' : 'public'
|
52
57
|
end
|
53
58
|
|
54
59
|
def create_dir(path)
|
data/lib/attachs/storages/s3.rb
CHANGED
@@ -4,7 +4,7 @@ module Attachs
|
|
4
4
|
|
5
5
|
cattr_accessor :config
|
6
6
|
|
7
|
-
def initialize(default)
|
7
|
+
def initialize(default, private)
|
8
8
|
if (Rails.env.test? and !default)
|
9
9
|
env = 'test'
|
10
10
|
elsif default
|
@@ -12,9 +12,9 @@ module Attachs
|
|
12
12
|
else
|
13
13
|
env = Rails.env
|
14
14
|
end
|
15
|
-
config
|
16
|
-
AWS.config
|
17
|
-
@
|
15
|
+
AWS.config access_key_id: config[env]['access_key_id'], secret_access_key: config[env]['secret_access_key']
|
16
|
+
@bucket = AWS::S3.new.buckets[config[env]['bucket']]
|
17
|
+
@private = private
|
18
18
|
end
|
19
19
|
|
20
20
|
def exists?(path)
|
@@ -26,12 +26,11 @@ module Attachs
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def url(path)
|
29
|
-
base_url = Rails.application.config.attachs.base_url
|
30
29
|
base_url.present? ? ::File.join(base_url, path) : object(path).public_url(secure: false)
|
31
30
|
end
|
32
31
|
|
33
32
|
def store(upload, path)
|
34
|
-
bucket.objects.create(path, Pathname.new(upload.path)).acl = :public_read
|
33
|
+
bucket.objects.create(path, Pathname.new(upload.path)).acl = private? ? :private : :public_read
|
35
34
|
end
|
36
35
|
|
37
36
|
def delete(path)
|
@@ -43,7 +42,7 @@ module Attachs
|
|
43
42
|
if upload.present?
|
44
43
|
cache[source] = upload.path
|
45
44
|
else
|
46
|
-
remote =
|
45
|
+
remote = create_tmp
|
47
46
|
remote.binmode
|
48
47
|
object(source).read { |chunk| remote.write(chunk) }
|
49
48
|
remote.close
|
@@ -51,7 +50,7 @@ module Attachs
|
|
51
50
|
cache[source] = remote.path
|
52
51
|
end
|
53
52
|
end
|
54
|
-
tmp =
|
53
|
+
tmp = create_tmp
|
55
54
|
yield Attachs::Magick::Image.new(cache[source], tmp.path)
|
56
55
|
store tmp, output
|
57
56
|
end
|
@@ -59,9 +58,21 @@ module Attachs
|
|
59
58
|
protected
|
60
59
|
|
61
60
|
attr_reader :bucket
|
61
|
+
|
62
|
+
def config
|
63
|
+
self.class.config
|
64
|
+
end
|
65
|
+
|
66
|
+
def base_url
|
67
|
+
Rails.application.config.attachs.base_url
|
68
|
+
end
|
69
|
+
|
70
|
+
def private?
|
71
|
+
@private
|
72
|
+
end
|
62
73
|
|
63
|
-
def
|
64
|
-
Tempfile.new
|
74
|
+
def create_tmp
|
75
|
+
Tempfile.new 's3'
|
65
76
|
end
|
66
77
|
|
67
78
|
def cache
|
data/lib/attachs/types/file.rb
CHANGED
@@ -3,6 +3,8 @@ module Attachs
|
|
3
3
|
class File
|
4
4
|
|
5
5
|
def initialize(source, options={})
|
6
|
+
@options = options
|
7
|
+
@deleted = false
|
6
8
|
if source.is_a? ActionDispatch::Http::UploadedFile or source.is_a? Rack::Test::UploadedFile
|
7
9
|
@upload = source
|
8
10
|
@stored = false
|
@@ -21,8 +23,10 @@ module Attachs
|
|
21
23
|
@default = true
|
22
24
|
@storage = build_storage
|
23
25
|
end
|
24
|
-
|
25
|
-
|
26
|
+
end
|
27
|
+
|
28
|
+
def private?
|
29
|
+
@options and @options[:private] == true
|
26
30
|
end
|
27
31
|
|
28
32
|
def default?
|
@@ -68,17 +72,17 @@ module Attachs
|
|
68
72
|
end
|
69
73
|
|
70
74
|
def realpath(*args)
|
71
|
-
return nil if deleted? or
|
75
|
+
return nil if deleted? or storage_type == :s3
|
72
76
|
(stored? ? storage.realpath(path(*args)) : upload.path).to_s
|
73
77
|
end
|
74
78
|
|
75
79
|
def url(*args)
|
76
|
-
return nil if deleted? or
|
80
|
+
return nil if deleted? or !stored?
|
77
81
|
storage.url(path(*args)).to_s
|
78
82
|
end
|
79
83
|
|
80
84
|
def store
|
81
|
-
if
|
85
|
+
if !stored? and upload?
|
82
86
|
@storage = build_storage
|
83
87
|
storage.store upload, destination_path
|
84
88
|
yield if block_given?
|
@@ -88,7 +92,7 @@ module Attachs
|
|
88
92
|
end
|
89
93
|
|
90
94
|
def delete
|
91
|
-
if
|
95
|
+
if !default? and stored? and exists?
|
92
96
|
storage.delete path
|
93
97
|
yield if block_given?
|
94
98
|
@storage = build_storage(:local) if upload?
|
@@ -101,9 +105,13 @@ module Attachs
|
|
101
105
|
|
102
106
|
attr_reader :upload, :storage, :options
|
103
107
|
|
108
|
+
def storage_type
|
109
|
+
Rails.application.config.attachs.storage
|
110
|
+
end
|
111
|
+
|
104
112
|
def build_storage(type=nil)
|
105
|
-
type
|
106
|
-
Attachs::Storages.const_get(
|
113
|
+
klass = (type || storage_type).to_s.classify
|
114
|
+
Attachs::Storages.const_get(klass).new default?, private?
|
107
115
|
end
|
108
116
|
|
109
117
|
def upload?
|
data/lib/attachs/types/image.rb
CHANGED
@@ -3,7 +3,7 @@ module Attachs
|
|
3
3
|
class Image < File
|
4
4
|
|
5
5
|
def presets
|
6
|
-
|
6
|
+
default_presets | parse_array_setting(options[:presets])
|
7
7
|
end
|
8
8
|
|
9
9
|
def store
|
@@ -11,26 +11,44 @@ module Attachs
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def delete
|
14
|
-
super { presets.each { |name|
|
14
|
+
super { presets.each { |name| delete_preset name } if presets.any? }
|
15
15
|
end
|
16
16
|
|
17
17
|
def generate_preset(name)
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
18
|
+
if settings = Rails.application.config.attachs.presets[name]
|
19
|
+
storage.magick destination_path, destination_path(name), upload do |image|
|
20
|
+
if settings.respond_to? :call
|
21
|
+
settings.call image
|
22
|
+
else
|
23
|
+
image.send "resize_to_#{settings[:method] || 'fill'}", settings[:width], settings[:height]
|
24
|
+
end
|
24
25
|
end
|
25
26
|
end
|
26
27
|
end
|
27
28
|
|
28
29
|
def delete_preset(name)
|
29
|
-
storage.delete path(name)
|
30
|
+
storage.delete path(name) if exists?(name)
|
30
31
|
end
|
31
32
|
|
32
33
|
protected
|
33
34
|
|
35
|
+
def parse_array_setting(value)
|
36
|
+
case value
|
37
|
+
when Symbol
|
38
|
+
[value]
|
39
|
+
when String
|
40
|
+
[value.to_sym]
|
41
|
+
when Array
|
42
|
+
value
|
43
|
+
else
|
44
|
+
[]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def default_presets
|
49
|
+
parse_array_setting Rails.application.config.attachs.default_presets
|
50
|
+
end
|
51
|
+
|
34
52
|
def store_path(*args)
|
35
53
|
::File.join 'images', (args[0] ? args[0].to_s.gsub('_', '-') : 'original')
|
36
54
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
class AttachmentContentTypeValidator < Attachs::Validators::Base
|
2
2
|
|
3
3
|
def validate_each(record, attribute, value)
|
4
|
-
if value.present? and
|
5
|
-
|
6
|
-
add_error record, attribute, '
|
4
|
+
if value.present? and !value.default?
|
5
|
+
if options[:in].exclude? value.extname.from(1)
|
6
|
+
add_error record, attribute, 'attachment_content_type', types: options[:in].to_sentence
|
7
7
|
end
|
8
8
|
end
|
9
9
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
class AttachmentPresenceValidator < Attachs::Validators::Base
|
2
2
|
|
3
3
|
def validate_each(record, attribute, value)
|
4
|
-
unless value.present? and value.exists? and
|
5
|
-
add_error record, attribute, '
|
4
|
+
unless value.present? and value.exists? and !value.default?
|
5
|
+
add_error record, attribute, 'attachment_presence'
|
6
6
|
end
|
7
7
|
end
|
8
8
|
|
@@ -2,9 +2,9 @@ class AttachmentSizeValidator < Attachs::Validators::Base
|
|
2
2
|
include ActionView::Helpers::NumberHelper
|
3
3
|
|
4
4
|
def validate_each(record, attribute, value)
|
5
|
-
if value.present? and
|
5
|
+
if value.present? and !value.default?
|
6
6
|
if options.has_key? :in
|
7
|
-
|
7
|
+
if options[:in].exclude? value.size
|
8
8
|
add_error record, attribute, 'attachment_size_in', min: number_to_human_size(options[:in].begin), max: number_to_human_size(options[:in].end)
|
9
9
|
end
|
10
10
|
else
|
@@ -18,10 +18,4 @@ class AttachmentSizeValidator < Attachs::Validators::Base
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
protected
|
22
|
-
|
23
|
-
def add_error(record, attribute, type, options)
|
24
|
-
super(record, attribute, "errors.messages.#{type}", options)
|
25
|
-
end
|
26
|
-
|
27
21
|
end
|