attachs 0.3.2 → 0.3.5
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.
- 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
|