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.
- checksums.yaml +4 -4
- data/MIT-LICENSE +1 -1
- data/README.md +83 -218
- data/Rakefile +1 -14
- data/lib/attachs.rb +98 -31
- data/lib/attachs/attachment.rb +301 -72
- data/lib/attachs/builder.rb +78 -0
- data/lib/attachs/collection.rb +84 -0
- data/lib/attachs/concern.rb +47 -0
- data/lib/attachs/configuration.rb +11 -0
- data/lib/attachs/console.rb +40 -0
- data/lib/attachs/extensions/active_record/base.rb +24 -0
- data/lib/attachs/extensions/active_record/validations/attachment_content_type_validator.rb +37 -0
- data/lib/attachs/extensions/active_record/validations/attachment_presence_validator.rb +27 -0
- data/lib/attachs/extensions/active_record/validations/attachment_size_validator.rb +55 -0
- data/lib/attachs/extensions/active_record/validations/attachment_validator.rb +24 -0
- data/lib/attachs/interpolations.rb +27 -0
- data/lib/attachs/jobs/base.rb +14 -0
- data/lib/attachs/jobs/delete_job.rb +15 -0
- data/lib/attachs/jobs/update_job.rb +11 -0
- data/lib/attachs/locales/en.yml +2 -6
- data/lib/attachs/locales/es.yml +2 -6
- data/lib/attachs/processors/base.rb +4 -14
- data/lib/attachs/processors/image.rb +45 -0
- data/lib/attachs/railtie.rb +7 -27
- data/lib/attachs/storages/base.rb +10 -59
- data/lib/attachs/storages/s3.rb +68 -63
- data/lib/attachs/version.rb +1 -1
- data/lib/generators/attachs/install/install_generator.rb +15 -0
- data/lib/generators/attachs/install/templates/initializer.rb +7 -0
- data/lib/generators/attachs/upload/templates/migration.rb +11 -0
- data/lib/generators/attachs/upload/templates/model.rb +19 -0
- data/lib/generators/attachs/upload/upload_generator.rb +24 -0
- data/lib/tasks/attachs.rake +12 -26
- data/test/attachment_test.rb +175 -12
- data/test/collection_test.rb +52 -0
- data/test/concern_test.rb +10 -0
- data/test/dummy/Rakefile +1 -2
- data/test/dummy/app/assets/javascripts/application.js +2 -2
- data/test/dummy/app/assets/stylesheets/application.css +6 -4
- data/test/dummy/app/models/product.rb +16 -0
- data/test/dummy/app/models/shop.rb +14 -0
- data/test/dummy/app/models/upload.rb +19 -0
- data/test/dummy/app/views/layouts/application.html.erb +9 -11
- data/test/dummy/bin/bundle +1 -0
- data/test/dummy/bin/rails +2 -1
- data/test/dummy/bin/rake +1 -0
- data/test/dummy/bin/setup +30 -0
- data/test/dummy/config.ru +1 -1
- data/test/dummy/config/application.rb +3 -2
- data/test/dummy/config/boot.rb +1 -1
- data/test/dummy/config/database.yml +4 -22
- data/test/dummy/config/database.yml.travis +3 -0
- data/test/dummy/config/environment.rb +1 -1
- data/test/dummy/config/environments/development.rb +15 -3
- data/test/dummy/config/environments/production.rb +21 -26
- data/test/dummy/config/environments/test.rb +10 -12
- data/test/dummy/config/initializers/assets.rb +11 -0
- data/test/dummy/config/initializers/attachs.rb +7 -21
- data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/test/dummy/config/initializers/mime_types.rb +1 -2
- data/test/dummy/config/initializers/session_store.rb +1 -1
- data/test/dummy/config/routes.rb +54 -0
- data/test/dummy/config/secrets.yml +24 -0
- data/test/dummy/db/migrate/20161024234003_create_shops.rb +11 -0
- data/test/dummy/db/migrate/20161024234029_create_products.rb +12 -0
- data/test/dummy/db/migrate/20161031135453_create_uploads.rb +11 -0
- data/test/dummy/db/schema.rb +27 -16
- data/test/dummy/log/development.log +61 -0
- data/test/dummy/log/test.log +5873 -0
- data/test/dummy/public/404.html +58 -55
- data/test/dummy/public/422.html +58 -55
- data/test/dummy/public/500.html +57 -54
- data/test/fixtures/big_file.txt +50 -0
- data/test/fixtures/big_image.jpg +0 -0
- data/test/fixtures/file.txt +1 -0
- data/test/fixtures/image.jpg +0 -0
- data/test/{dummy/test/fixtures/file.txt → fixtures/small_file.txt} +0 -0
- data/test/fixtures/small_image.jpg +0 -0
- data/test/generator_test.rb +14 -6
- data/test/helper_test.rb +28 -0
- data/test/query_test.rb +26 -0
- data/test/support/storage_helper.rb +65 -0
- data/test/task_test.rb +69 -0
- data/test/test_helper.rb +6 -45
- data/test/upload_test.rb +27 -0
- data/test/validator_test.rb +160 -0
- metadata +114 -68
- data/lib/attachs/active_record/base.rb +0 -103
- data/lib/attachs/active_record/connection_adapters.rb +0 -40
- data/lib/attachs/active_record/migration.rb +0 -17
- data/lib/attachs/active_record/validators.rb +0 -7
- data/lib/attachs/active_record/validators/attachment_content_type_validator.rb +0 -30
- data/lib/attachs/active_record/validators/attachment_presence_validator.rb +0 -22
- data/lib/attachs/active_record/validators/attachment_size_validator.rb +0 -47
- data/lib/attachs/processors/thumbnail.rb +0 -69
- data/lib/attachs/storages/local.rb +0 -95
- data/lib/attachs/types/base.rb +0 -22
- data/lib/attachs/types/default.rb +0 -29
- data/lib/attachs/types/regular.rb +0 -21
- data/lib/generators/attachs/install_generator.rb +0 -13
- data/lib/generators/attachs/templates/attachs.rb +0 -2
- data/test/dummy/README.rdoc +0 -28
- data/test/dummy/app/models/medium.rb +0 -5
- data/test/dummy/app/models/picture.rb +0 -2
- data/test/dummy/config/initializers/secret_token.rb +0 -13
- data/test/dummy/config/s3.yml +0 -15
- data/test/dummy/db/migrate/20140808012639_create_media.rb +0 -11
- data/test/dummy/test/fixtures/image.gif +0 -0
- data/test/local_storage_test.rb +0 -72
- data/test/migration_test.rb +0 -65
- data/test/processor_test.rb +0 -49
- data/test/s3_storage_tes.rb +0 -66
- data/test/tasks_test.rb +0 -57
- 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,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
|
data/lib/attachs/locales/en.yml
CHANGED
@@ -1,9 +1,5 @@
|
|
1
1
|
en:
|
2
2
|
errors:
|
3
3
|
messages:
|
4
|
-
|
5
|
-
|
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}"
|