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
@@ -0,0 +1,84 @@
1
+ module Attachs
2
+ class Collection
3
+
4
+ delegate(
5
+ :map, :each, :size, :length, :count, :reject, :select, :any?,
6
+ :all?, :none?, :first, :second, :last, :[],
7
+ to: :to_a
8
+ )
9
+
10
+ attr_reader :record, :record_attribute, :options
11
+
12
+ def initialize(record, record_attribute, options, collection=[])
13
+ @record = record
14
+ @record_attribute = record_attribute
15
+ @options = options
16
+ @attachments = build_attachments(collection)
17
+ end
18
+
19
+ %i(save destroy persist unpersist).each do |name|
20
+ define_method name do
21
+ each do |attachment|
22
+ attachment.send name
23
+ end
24
+ end
25
+ end
26
+
27
+ def to_a
28
+ attachments.sort_by do |attachment|
29
+ [(attachment.position ? 0 : 1), (attachment.position || 0)]
30
+ end
31
+ end
32
+ alias_method :to_ary, :to_a
33
+
34
+ def find(id)
35
+ to_a.find do |attachment|
36
+ attachment.id == id
37
+ end
38
+ end
39
+
40
+ def []=(index, value)
41
+ if attachment = to_a[index]
42
+ attachment.assign value
43
+ else
44
+ append value
45
+ end
46
+ end
47
+
48
+ def assign(values)
49
+ if values.is_a?(Array)
50
+ values.each.with_index do |value, index|
51
+ if attachment = attachments[index]
52
+ attachment.assign value
53
+ else
54
+ append value
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+ def append(value)
61
+ attachment = new
62
+ attachment.assign value
63
+ end
64
+ alias_method :<<, :append
65
+
66
+ def new
67
+ attachment = Attachment.new(record, record_attribute, options)
68
+ attachments << attachment
69
+ attachment
70
+ end
71
+ alias_method :build, :new
72
+
73
+ private
74
+
75
+ attr_reader :attachments
76
+
77
+ def build_attachments(collection)
78
+ collection.map do |attributes|
79
+ Attachment.new record, record_attribute, options, attributes
80
+ end
81
+ end
82
+
83
+ end
84
+ end
@@ -0,0 +1,47 @@
1
+ module Attachs
2
+ module Concern
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ before_save :persist_attachments
7
+ after_commit :save_attachments, on: %i(create update)
8
+ after_commit :destroy_attachments, on: :destroy
9
+ after_rollback :unpersist_attachments
10
+ end
11
+
12
+ def reload(options=nil)
13
+ super.tap do
14
+ self.class.attachments.keys.each do |attribute|
15
+ instance_variable_set "@#{attribute}", nil
16
+ end
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ %i(save destroy persist unpersist).each do |method|
23
+ define_method "#{method}_attachments" do
24
+ self.class.attachments.keys.each do |attribute|
25
+ send(attribute).send method
26
+ end
27
+ end
28
+ end
29
+
30
+ module ClassMethods
31
+
32
+ def inherited(subclass)
33
+ subclass.instance_variable_set :@attachments, @attachments
34
+ super
35
+ end
36
+
37
+ def attachments
38
+ @attachments ||= {}
39
+ end
40
+
41
+ def attachable?
42
+ attachments.any?
43
+ end
44
+
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,11 @@
1
+ module Attachs
2
+ class Configuration
3
+
4
+ attr_accessor :convert_options, :base_url, :region, :bucket
5
+
6
+ def add_interpolation(*args, &block)
7
+ Attachs.interpolations.add *args, &block
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,40 @@
1
+ module Attachs
2
+ class Console
3
+ class << self
4
+
5
+ def find_content_type(path)
6
+ run "file -Ib '#{path}'" do |output|
7
+ output.split(';').first
8
+ end
9
+ end
10
+
11
+ def find_dimensions(path)
12
+ run "gm identify -format %wx%h '#{path}'" do |output|
13
+ output.split('x').map &:to_i
14
+ end
15
+ end
16
+
17
+ def convert(source_path, destination_path, options=nil)
18
+ run "gm convert '#{source_path}' #{options} '#{destination_path}'".squeeze(' ')
19
+ end
20
+
21
+ private
22
+
23
+ def run(cmd)
24
+ Rails.logger.info "Running: #{cmd}"
25
+ stdout, stderr, status = Open3.capture3(cmd)
26
+ if status.success?
27
+ output = stdout.strip
28
+ if block_given?
29
+ yield output
30
+ else
31
+ output
32
+ end
33
+ else
34
+ false
35
+ end
36
+ end
37
+
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,24 @@
1
+ module Attachs
2
+ module Extensions
3
+ module ActiveRecord
4
+ module Base
5
+ extend ActiveSupport::Concern
6
+
7
+ module ClassMethods
8
+
9
+ def has_attachment(*args)
10
+ builder = Builder.new(self)
11
+ builder.define *args
12
+ end
13
+
14
+ def has_attachments(*args)
15
+ options = args.extract_options!
16
+ options[:multiple] = true
17
+ has_attachment *args.append(options)
18
+ end
19
+
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,37 @@
1
+ module Attachs
2
+ module Extensions
3
+ module ActiveRecord
4
+ module Validations
5
+ extend ActiveSupport::Concern
6
+
7
+ class AttachmentContentTypeValidator < AttachmentValidator
8
+
9
+ def validate_one(record, attribute, attachment)
10
+ unless attachment.blank?
11
+ if options.has_key?(:with)
12
+ if options[:with] !~ attachment.content_type
13
+ record.errors.add attribute, :invalid
14
+ attachment.errors.add :content_type, :not_allowed
15
+ end
16
+ elsif options.has_key?(:in) || options.has_key?(:within)
17
+ list = (options[:in] || options[:within])
18
+ if list.exclude?(attachment.content_type)
19
+ record.errors.add attribute, :invalid
20
+ attachment.errors.add :content_type, :not_listed, list: list.to_sentence
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ end
27
+ module ClassMethods
28
+
29
+ def validates_attachment_content_type_of(*attr_names)
30
+ validates_with AttachmentContentTypeValidator, _merge_attributes(attr_names)
31
+ end
32
+
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,27 @@
1
+ module Attachs
2
+ module Extensions
3
+ module ActiveRecord
4
+ module Validations
5
+ extend ActiveSupport::Concern
6
+
7
+ class AttachmentPresenceValidator < AttachmentValidator
8
+
9
+ def validate_one(record, attribute, attachment)
10
+ unless attachment.blank?
11
+ record.errors.add attribute, :invalid
12
+ attachment.errors.add :base, :blank
13
+ end
14
+ end
15
+
16
+ end
17
+ module ClassMethods
18
+
19
+ def validates_attachment_presence_of(*attr_names)
20
+ validates_with AttachmentPresenceValidator, _merge_attributes(attr_names)
21
+ end
22
+
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,55 @@
1
+ module Attachs
2
+ module Extensions
3
+ module ActiveRecord
4
+ module Validations
5
+ extend ActiveSupport::Concern
6
+
7
+ class AttachmentSizeValidator < AttachmentValidator
8
+ CHECKS = { less_than: :<, less_than_or_equal_to: :<=, greater_than: :>, greater_than_or_equal_to: :>= }
9
+
10
+ def initialize(options)
11
+ if range = (options[:in] || options[:within])
12
+ options[:less_than_or_equal_to] = range.max
13
+ options[:greater_than_or_equal_to] = range.min
14
+ end
15
+ super
16
+ end
17
+
18
+ def validate_one(record, attribute, attachment)
19
+ unless attachment.blank?
20
+ CHECKS.each do |name, operator|
21
+ if options.has_key?(name)
22
+ other = options[name]
23
+ case other
24
+ when Symbol
25
+ other = record.send(other)
26
+ when Proc
27
+ other = other.call(record)
28
+ end
29
+ unless attachment.size.send(operator, other)
30
+ record.errors.add attribute, :invalid
31
+ attachment.errors.add :size, name, count: humanize_size(other)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def humanize_size(size)
41
+ ActiveSupport::NumberHelper.number_to_human_size size
42
+ end
43
+
44
+ end
45
+ module ClassMethods
46
+
47
+ def validates_attachment_size_of(*attr_names)
48
+ validates_with AttachmentSizeValidator, _merge_attributes(attr_names)
49
+ end
50
+
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,24 @@
1
+ module Attachs
2
+ module Extensions
3
+ module ActiveRecord
4
+ module Validations
5
+ extend ActiveSupport::Concern
6
+
7
+ class AttachmentValidator < ActiveModel::EachValidator
8
+
9
+ def validate_each(record, attribute, attachment_or_collection)
10
+ case attachment_or_collection
11
+ when Collection
12
+ attachment_or_collection.each do |attachment|
13
+ validate_one record, attribute, attachment
14
+ end
15
+ when Attachment
16
+ validate_one record, attribute, attachment_or_collection
17
+ end
18
+ end
19
+
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,27 @@
1
+ module Attachs
2
+ class Interpolations
3
+
4
+ def exist?(name)
5
+ registry.has_key? name
6
+ end
7
+
8
+ def find(name)
9
+ if exist?(name)
10
+ registry[name]
11
+ else
12
+ raise "Interpolation #{name} not found"
13
+ end
14
+ end
15
+
16
+ def add(name, &block)
17
+ registry[name] = block
18
+ end
19
+
20
+ private
21
+
22
+ def registry
23
+ @registry ||= {}
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,14 @@
1
+ module Attachs
2
+ module Jobs
3
+ class Base < ActiveJob::Base
4
+ queue_as :default
5
+
6
+ private
7
+
8
+ def storage
9
+ Attachs.storage
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,15 @@
1
+ module Attachs
2
+ module Jobs
3
+ class DeleteJob < Base
4
+
5
+ def perform(paths)
6
+ paths.each do |path|
7
+ if storage.exist?(path)
8
+ storage.delete path
9
+ end
10
+ end
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ module Attachs
2
+ module Jobs
3
+ class UpdateJob < Base
4
+
5
+ def perform(record, record_attribute)
6
+ record.send(record_attribute).update_paths
7
+ end
8
+
9
+ end
10
+ end
11
+ end
@@ -1,9 +1,5 @@
1
1
  en:
2
2
  errors:
3
3
  messages:
4
- attachment_presence: "can't be blank"
5
- attachment_content_type_with: "has not allowed type"
6
- attachment_content_type_in: "must be of one of the following types: %{types}"
7
- attachment_size_less_than: "size must be less than %{count}"
8
- attachment_size_greater_than: "size must be greater than %{count}"
9
- attachment_size_in: "size must be between %{min} and %{max}"
4
+ not_allowed: "not allowed"
5
+ not_listed: "must be one of the following: %{list}"