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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6376bae7f409923ee076e8f0b4eba342e0b107b4
4
- data.tar.gz: c9cf65c444e4e9538ee0d99fdd7a77a5b26a6f04
3
+ metadata.gz: d4b7e169e9f30ad2bf78cb7f234ff71814200ad6
4
+ data.tar.gz: b8a1b2b599f222bf759809834c9e492389629ef0
5
5
  SHA512:
6
- metadata.gz: e34990d1ba9a0f1dbb33300c3bea569d1ecde6645368f7f3f269d2e2742c6d9b0ea2e288910f03d28373cfa86a82705ca6281168b4cf7c311f2290a917f2cbe6
7
- data.tar.gz: 57f8213edd2ddbafd31ea2257a7fb9c64ad833a06cdf99259156bc3ed6bd64d8f5a067f339d88c94c6b85da2e090b9b4b53db717a3cb2a4a183afa5ff0af45cd
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:Engine: '/' # Will be use to generate on the fly missing image presets
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
- define_attachable_attribute_methods attr.to_sym, options
93
- define_default_validations attr.to_sym, options
94
- attachments[attr.to_sym] = options
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 define_default_validations(attr, options)
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 or (value.is_a? String and value =~ /^[a-zA-Z0-9_-]+\.[a-zA-z]+$/)
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
- if attribute_present? attr and value == '1'
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)
@@ -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 = self.class.config[env]
16
- AWS.config access_key_id: config['access_key_id'], secret_access_key: config['secret_access_key']
17
- @bucket = AWS::S3.new.buckets[config['bucket']]
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 = create_tmp_file
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 = create_tmp_file
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 create_tmp_file
64
- Tempfile.new('s3')
74
+ def create_tmp
75
+ Tempfile.new 's3'
65
76
  end
66
77
 
67
78
  def cache
@@ -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
- @deleted = false
25
- @options = options
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 Rails.application.config.attachs.storage == :s3
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 not stored?
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 not stored? and upload?
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 not default? and stored? and exists?
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 ||= Rails.application.config.attachs.storage
106
- Attachs::Storages.const_get(type.to_s.classify).new default?
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?
@@ -3,7 +3,7 @@ module Attachs
3
3
  class Image < File
4
4
 
5
5
  def presets
6
- Rails.application.config.attachs.default_presets | (options[:presets] || [])
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| storage.delete path(name) if exists?(name) } if presets.any? }
14
+ super { presets.each { |name| delete_preset name } if presets.any? }
15
15
  end
16
16
 
17
17
  def generate_preset(name)
18
- storage.magick destination_path, destination_path(name), upload do |image|
19
- settings = Rails.application.config.attachs.presets[name]
20
- if settings.respond_to? :call
21
- settings.call image
22
- else
23
- image.send "resize_to_#{settings[:method] || 'fill'}", settings[:width], settings[:height]
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 not value.default?
5
- unless options[:in].include? value.extname.from(1)
6
- add_error record, attribute, 'errors.messages.attachment_content_type', types: options[:in].to_sentence
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 not value.default?
5
- add_error record, attribute, 'errors.messages.attachment_presence'
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 not value.default?
5
+ if value.present? and !value.default?
6
6
  if options.has_key? :in
7
- unless options[:in].include? value.size
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