attachs 0.4.5 → 4.0.0.0

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.
Files changed (115) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +83 -218
  4. data/Rakefile +1 -14
  5. data/lib/attachs.rb +98 -31
  6. data/lib/attachs/attachment.rb +301 -72
  7. data/lib/attachs/builder.rb +78 -0
  8. data/lib/attachs/collection.rb +84 -0
  9. data/lib/attachs/concern.rb +47 -0
  10. data/lib/attachs/configuration.rb +11 -0
  11. data/lib/attachs/console.rb +40 -0
  12. data/lib/attachs/extensions/active_record/base.rb +24 -0
  13. data/lib/attachs/extensions/active_record/validations/attachment_content_type_validator.rb +37 -0
  14. data/lib/attachs/extensions/active_record/validations/attachment_presence_validator.rb +27 -0
  15. data/lib/attachs/extensions/active_record/validations/attachment_size_validator.rb +55 -0
  16. data/lib/attachs/extensions/active_record/validations/attachment_validator.rb +24 -0
  17. data/lib/attachs/interpolations.rb +27 -0
  18. data/lib/attachs/jobs/base.rb +14 -0
  19. data/lib/attachs/jobs/delete_job.rb +15 -0
  20. data/lib/attachs/jobs/update_job.rb +11 -0
  21. data/lib/attachs/locales/en.yml +2 -6
  22. data/lib/attachs/locales/es.yml +2 -6
  23. data/lib/attachs/processors/base.rb +4 -14
  24. data/lib/attachs/processors/image.rb +45 -0
  25. data/lib/attachs/railtie.rb +7 -27
  26. data/lib/attachs/storages/base.rb +10 -59
  27. data/lib/attachs/storages/s3.rb +68 -63
  28. data/lib/attachs/version.rb +1 -1
  29. data/lib/generators/attachs/install/install_generator.rb +15 -0
  30. data/lib/generators/attachs/install/templates/initializer.rb +7 -0
  31. data/lib/generators/attachs/upload/templates/migration.rb +11 -0
  32. data/lib/generators/attachs/upload/templates/model.rb +19 -0
  33. data/lib/generators/attachs/upload/upload_generator.rb +24 -0
  34. data/lib/tasks/attachs.rake +12 -26
  35. data/test/attachment_test.rb +175 -12
  36. data/test/collection_test.rb +52 -0
  37. data/test/concern_test.rb +10 -0
  38. data/test/dummy/Rakefile +1 -2
  39. data/test/dummy/app/assets/javascripts/application.js +2 -2
  40. data/test/dummy/app/assets/stylesheets/application.css +6 -4
  41. data/test/dummy/app/models/product.rb +16 -0
  42. data/test/dummy/app/models/shop.rb +14 -0
  43. data/test/dummy/app/models/upload.rb +19 -0
  44. data/test/dummy/app/views/layouts/application.html.erb +9 -11
  45. data/test/dummy/bin/bundle +1 -0
  46. data/test/dummy/bin/rails +2 -1
  47. data/test/dummy/bin/rake +1 -0
  48. data/test/dummy/bin/setup +30 -0
  49. data/test/dummy/config.ru +1 -1
  50. data/test/dummy/config/application.rb +3 -2
  51. data/test/dummy/config/boot.rb +1 -1
  52. data/test/dummy/config/database.yml +4 -22
  53. data/test/dummy/config/database.yml.travis +3 -0
  54. data/test/dummy/config/environment.rb +1 -1
  55. data/test/dummy/config/environments/development.rb +15 -3
  56. data/test/dummy/config/environments/production.rb +21 -26
  57. data/test/dummy/config/environments/test.rb +10 -12
  58. data/test/dummy/config/initializers/assets.rb +11 -0
  59. data/test/dummy/config/initializers/attachs.rb +7 -21
  60. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  61. data/test/dummy/config/initializers/mime_types.rb +1 -2
  62. data/test/dummy/config/initializers/session_store.rb +1 -1
  63. data/test/dummy/config/routes.rb +54 -0
  64. data/test/dummy/config/secrets.yml +24 -0
  65. data/test/dummy/db/migrate/20161024234003_create_shops.rb +11 -0
  66. data/test/dummy/db/migrate/20161024234029_create_products.rb +12 -0
  67. data/test/dummy/db/migrate/20161031135453_create_uploads.rb +11 -0
  68. data/test/dummy/db/schema.rb +27 -16
  69. data/test/dummy/log/development.log +61 -0
  70. data/test/dummy/log/test.log +5873 -0
  71. data/test/dummy/public/404.html +58 -55
  72. data/test/dummy/public/422.html +58 -55
  73. data/test/dummy/public/500.html +57 -54
  74. data/test/fixtures/big_file.txt +50 -0
  75. data/test/fixtures/big_image.jpg +0 -0
  76. data/test/fixtures/file.txt +1 -0
  77. data/test/fixtures/image.jpg +0 -0
  78. data/test/{dummy/test/fixtures/file.txt → fixtures/small_file.txt} +0 -0
  79. data/test/fixtures/small_image.jpg +0 -0
  80. data/test/generator_test.rb +14 -6
  81. data/test/helper_test.rb +28 -0
  82. data/test/query_test.rb +26 -0
  83. data/test/support/storage_helper.rb +65 -0
  84. data/test/task_test.rb +69 -0
  85. data/test/test_helper.rb +6 -45
  86. data/test/upload_test.rb +27 -0
  87. data/test/validator_test.rb +160 -0
  88. metadata +114 -68
  89. data/lib/attachs/active_record/base.rb +0 -103
  90. data/lib/attachs/active_record/connection_adapters.rb +0 -40
  91. data/lib/attachs/active_record/migration.rb +0 -17
  92. data/lib/attachs/active_record/validators.rb +0 -7
  93. data/lib/attachs/active_record/validators/attachment_content_type_validator.rb +0 -30
  94. data/lib/attachs/active_record/validators/attachment_presence_validator.rb +0 -22
  95. data/lib/attachs/active_record/validators/attachment_size_validator.rb +0 -47
  96. data/lib/attachs/processors/thumbnail.rb +0 -69
  97. data/lib/attachs/storages/local.rb +0 -95
  98. data/lib/attachs/types/base.rb +0 -22
  99. data/lib/attachs/types/default.rb +0 -29
  100. data/lib/attachs/types/regular.rb +0 -21
  101. data/lib/generators/attachs/install_generator.rb +0 -13
  102. data/lib/generators/attachs/templates/attachs.rb +0 -2
  103. data/test/dummy/README.rdoc +0 -28
  104. data/test/dummy/app/models/medium.rb +0 -5
  105. data/test/dummy/app/models/picture.rb +0 -2
  106. data/test/dummy/config/initializers/secret_token.rb +0 -13
  107. data/test/dummy/config/s3.yml +0 -15
  108. data/test/dummy/db/migrate/20140808012639_create_media.rb +0 -11
  109. data/test/dummy/test/fixtures/image.gif +0 -0
  110. data/test/local_storage_test.rb +0 -72
  111. data/test/migration_test.rb +0 -65
  112. data/test/processor_test.rb +0 -49
  113. data/test/s3_storage_tes.rb +0 -66
  114. data/test/tasks_test.rb +0 -57
  115. data/test/validators_test.rb +0 -100
@@ -1,103 +0,0 @@
1
- module Attachs
2
- module ActiveRecord
3
- module Base
4
- extend ActiveSupport::Concern
5
-
6
- protected
7
-
8
- def attachments
9
- @attachments ||= {}.tap do |instances|
10
- self.class.attachments.each do |attr, options|
11
- instances[attr] = Attachs::Attachment.new(self, attr, options)
12
- end
13
- end
14
- end
15
-
16
- def queued_attachments
17
- @queued_attachments ||= { process: {}, destroy: {} }
18
- end
19
-
20
- def queue_attachment(attr, options, value)
21
- unless queued_attachments[:destroy].has_key? attr
22
- queued_attachments[:destroy][attr] = attachments[attr]
23
- end
24
- if queued_attachments[:process].has_key? attr and value.nil?
25
- attachments[attr]
26
- else
27
- queued_attachments[:process][attr] = Attachs::Attachment.new(self, attr, options, value)
28
- end
29
- end
30
-
31
- def commit_attachments
32
- self.class.attachments.each do |attr, options|
33
- send "destroy_#{attr}=", nil
34
- end
35
- queued_attachments[:destroy].each do |attr, attachment|
36
- attachment.destroy
37
- end
38
- queued_attachments[:process].each do |attr, attachment|
39
- attachment.process
40
- end
41
- queued_attachments[:destroy] = {}
42
- queued_attachments[:process] = {}
43
- end
44
-
45
- def destroy_attachments
46
- self.class.attachments.each do |attr, options|
47
- send(attr).destroy
48
- end
49
- end
50
-
51
- module ClassMethods
52
-
53
- def has_attached_file(*args)
54
- options = args.extract_options!
55
- unless attachable?
56
- make_attachable
57
- end
58
- args.each do |attr|
59
- define_attachment_methods attr, options
60
- attachments[attr] = options
61
- end
62
- end
63
-
64
- def attachments
65
- @attachments ||= {}
66
- end
67
-
68
- def attachable?
69
- attachments.any?
70
- end
71
-
72
- def inherited(subclass)
73
- subclass.instance_variable_set :@attachments, @attachments
74
- super
75
- end
76
-
77
- protected
78
-
79
- def make_attachable
80
- after_save :commit_attachments
81
- after_destroy :destroy_attachments
82
- end
83
-
84
- def define_attachment_methods(attr, options)
85
- define_method "#{attr}=" do |value|
86
- attachments[attr] = queue_attachment(attr, options, value)
87
- end
88
- define_method attr do
89
- attachments[attr]
90
- end
91
- attr_reader "destroy_#{attr}"
92
- define_method "destroy_#{attr}=" do |value|
93
- instance_variable_set "@destroy_#{attr}", value
94
- if [1, '1', true].include?(value) and !send(attr).upload?
95
- send "#{attr}=", nil
96
- end
97
- end
98
- end
99
-
100
- end
101
- end
102
- end
103
- end
@@ -1,40 +0,0 @@
1
- module Attachs
2
- module ActiveRecord
3
- module ConnectionAdapters
4
- COLUMNS = {
5
- filename: 'string',
6
- content_type: 'string',
7
- size: 'integer',
8
- updated_at: 'datetime'
9
- }
10
-
11
- module AbstractAdapter
12
- def add_attachment(table_name, *attachment_names)
13
- attachment_names.each do |attachment_name|
14
- COLUMNS.each do |column_name, column_type|
15
- add_column table_name, "#{attachment_name}_#{column_name}", column_type
16
- end
17
- end
18
- end
19
-
20
- def remove_attachment(table_name, *attachment_names)
21
- attachment_names.each do |attachment_name|
22
- COLUMNS.each do |column_name, column_type|
23
- remove_column table_name, "#{attachment_name}_#{column_name}"
24
- end
25
- end
26
- end
27
- end
28
-
29
- module TableDefinition
30
- def attachment(*attachment_names)
31
- attachment_names.each do |attachment_name|
32
- COLUMNS.each do |column_name, column_type|
33
- column "#{attachment_name}_#{column_name}", column_type
34
- end
35
- end
36
- end
37
- end
38
- end
39
- end
40
- end
@@ -1,17 +0,0 @@
1
- module Attachs
2
- module ActiveRecord
3
- module Migration
4
- module CommandRecorder
5
- def add_attachment(*args)
6
- record :add_attachment, args
7
- end
8
-
9
- private
10
-
11
- def invert_add_attachment(*args)
12
- [:remove_attachment, args]
13
- end
14
- end
15
- end
16
- end
17
- end
@@ -1,7 +0,0 @@
1
- module Attachs
2
- module ActiveRecord
3
- module Validators
4
- extend ActiveSupport::Concern
5
- end
6
- end
7
- end
@@ -1,30 +0,0 @@
1
- module Attachs
2
- module ActiveRecord
3
- module Validators
4
- class AttachmentContentTypeValidator < ActiveModel::EachValidator
5
-
6
- def validate_each(record, attribute, value)
7
- if value.exists?
8
- if options.has_key? :with
9
- if options[:with] !~ value.content_type
10
- record.errors.add attribute, :attachment_content_type_with
11
- end
12
- elsif options.has_key? :in
13
- if options[:in].exclude? value.content_type
14
- record.errors.add attribute, :attachment_content_type_in, types: options[:in].to_sentence
15
- end
16
- end
17
- end
18
- end
19
-
20
- end
21
- module ClassMethods
22
-
23
- def validates_attachment_content_type_of(*attr_names)
24
- validates_with AttachmentContentTypeValidator, _merge_attributes(attr_names)
25
- end
26
-
27
- end
28
- end
29
- end
30
- end
@@ -1,22 +0,0 @@
1
- module Attachs
2
- module ActiveRecord
3
- module Validators
4
- class AttachmentPresenceValidator < ActiveModel::EachValidator
5
-
6
- def validate_each(record, attribute, value)
7
- if value.blank?
8
- record.errors.add attribute, :attachment_presence
9
- end
10
- end
11
-
12
- end
13
- module ClassMethods
14
-
15
- def validates_attachment_presence_of(*attr_names)
16
- validates_with AttachmentPresenceValidator, _merge_attributes(attr_names)
17
- end
18
-
19
- end
20
- end
21
- end
22
- end
@@ -1,47 +0,0 @@
1
- module Attachs
2
- module ActiveRecord
3
- module Validators
4
- class AttachmentSizeValidator < ActiveModel::EachValidator
5
- include ActionView::Helpers::NumberHelper
6
-
7
- def validate_each(record, attribute, value)
8
- if value.exists?
9
- if options.has_key? :in
10
- if options[:in].exclude? value.size
11
- record.errors.add(
12
- attribute,
13
- :attachment_size_in,
14
- min: number_to_human_size(options[:in].begin),
15
- max: number_to_human_size(options[:in].end)
16
- )
17
- end
18
- else
19
- if options.has_key? :less_than and value.size > options[:less_than]
20
- record.errors.add(
21
- attribute,
22
- :attachment_size_less_than,
23
- count: number_to_human_size(options[:less_than])
24
- )
25
- end
26
- if options.has_key? :greater_than and value.size < options[:greater_than]
27
- record.errors.add(
28
- attribute,
29
- :attachment_size_greater_than,
30
- count: number_to_human_size(options[:greater_than])
31
- )
32
- end
33
- end
34
- end
35
- end
36
-
37
- end
38
- module ClassMethods
39
-
40
- def validates_attachment_size_of(*attr_names)
41
- validates_with AttachmentSizeValidator, _merge_attributes(attr_names)
42
- end
43
-
44
- end
45
- end
46
- end
47
- end
@@ -1,69 +0,0 @@
1
- module Attachs
2
- module Processors
3
- class Thumbnail < Base
4
-
5
- def initialize(attachment, source)
6
- super
7
- @width, @height = dimensions(source)
8
- end
9
-
10
- def process(style, destination)
11
- new_width, new_height, strategy, options = geometry(style)
12
- resize source, width, height, new_width, new_height, strategy, options, destination
13
- end
14
-
15
- protected
16
-
17
- attr_reader :width, :height
18
-
19
- def geometry(style)
20
- geometry = Attachs.config.styles[style]
21
- width, height = geometry.scan(/[^x]+/).map(&:to_i)
22
- case geometry[/!|#/]
23
- when '#'
24
- strategy = 'cover'
25
- when '!'
26
- strategy = 'force'
27
- else
28
- strategy = 'contain'
29
- end
30
- options = Attachs.config.convert_options[style]
31
- [width, height, strategy, options]
32
- end
33
-
34
- def resize(source, width, height, new_width, new_height, strategy, custom_options, destination)
35
- case strategy
36
- when 'cover'
37
- ratio = [new_width.to_f/width, new_height.to_f/height].max
38
- options = "-resize #{(ratio*width).ceil}x#{(ratio*height).ceil} -gravity center -crop #{new_width}x#{new_height}+0+0"
39
- when 'force'
40
- options = "-resize #{new_width}x#{new_height}\!"
41
- when 'contain'
42
- options = "-resize #{new_width}x#{new_height}"
43
- end
44
- if global_options = Attachs.config.global_convert_options
45
- options << " #{global_options}"
46
- end
47
- if custom_options
48
- options << " #{custom_options}"
49
- end
50
- convert source, options, destination
51
- end
52
-
53
- def dimensions(source)
54
- if output = identify(source, '-format %wx%h')
55
- output.split('x').map(&:to_i)
56
- end
57
- end
58
-
59
- def convert(source, options, destination)
60
- run "convert '#{source}' #{options} '#{destination}'"
61
- end
62
-
63
- def identify(source, options)
64
- run "identify #{options} '#{source}'"
65
- end
66
-
67
- end
68
- end
69
- end
@@ -1,95 +0,0 @@
1
- module Attachs
2
- module Storages
3
- class Local < Base
4
-
5
- def url(*args)
6
- if attachment.url?
7
- options = args.extract_options!
8
- style = (args[0] || :original)
9
- base_url.join(path(style)).to_s.tap do |url|
10
- if find_option(options, :cachebuster, Attachs.config.cachebuster)
11
- url << "?#{attachment.updated_at.to_i}"
12
- end
13
- end
14
- end
15
- end
16
-
17
- def process(force=false)
18
- if attachment.upload?
19
- FileUtils.mkdir_p realpath.dirname
20
- attachment.upload.rewind
21
- File.open(realpath, 'wb') do |file|
22
- while chunk = attachment.upload.read(16 * 1024)
23
- file.write chunk
24
- end
25
- end
26
- attachment.uploaded!
27
- end
28
- process_styles force
29
- end
30
-
31
- def process_styles(force=false)
32
- if attachment.image?
33
- attachment.processors.each do |klass|
34
- processor = klass.new(attachment, realpath)
35
- attachment.styles.each do |style|
36
- if force == true
37
- delete realpath(style)
38
- end
39
- unless File.exist? realpath(style)
40
- FileUtils.mkdir_p realpath(style).dirname
41
- processor.process style, realpath(style)
42
- end
43
- end
44
- end
45
- end
46
- end
47
-
48
- def destroy
49
- delete realpath
50
- destroy_styles
51
- end
52
-
53
- def destroy_styles
54
- if attachment.image?
55
- attachment.styles.each do |style|
56
- delete realpath(style)
57
- end
58
- end
59
- end
60
-
61
- protected
62
-
63
- def delete(realpath)
64
- if File.exist? realpath
65
- File.delete realpath
66
- end
67
- end
68
-
69
- def realpath(style=:original)
70
- base_path.join(path(style))
71
- end
72
-
73
- def base_path
74
- @base_path ||= begin
75
- if attachment.private?
76
- Rails.root.join 'private'
77
- else
78
- Rails.root.join 'public'
79
- end
80
- end
81
- end
82
-
83
- def base_url
84
- @base_url ||= begin
85
- if Attachs.config.base_url.present?
86
- Pathname.new Attachs.config.base_url
87
- else
88
- Pathname.new '/'
89
- end
90
- end
91
- end
92
-
93
- end
94
- end
95
- end
@@ -1,22 +0,0 @@
1
- module Attachs
2
- module Types
3
- class Base
4
-
5
- def initialize(attachment)
6
- @attachment = attachment
7
- end
8
-
9
- protected
10
-
11
- attr_reader :attachment
12
-
13
- def storage
14
- @storage ||= begin
15
- klass = (attachment.options[:storage] || Attachs.config.default_storage).to_s.classify
16
- Attachs::Storages.const_get(klass).new(attachment)
17
- end
18
- end
19
-
20
- end
21
- end
22
- end