activestorage 5.2.7.1 → 6.1.4.6

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activestorage might be problematic. Click here for more details.

Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +225 -93
  3. data/MIT-LICENSE +1 -1
  4. data/README.md +43 -8
  5. data/app/assets/javascripts/activestorage.js +5 -2
  6. data/app/controllers/active_storage/base_controller.rb +13 -4
  7. data/app/controllers/active_storage/blobs/proxy_controller.rb +14 -0
  8. data/app/controllers/active_storage/{blobs_controller.rb → blobs/redirect_controller.rb} +3 -3
  9. data/app/controllers/active_storage/direct_uploads_controller.rb +2 -2
  10. data/app/controllers/active_storage/disk_controller.rb +13 -22
  11. data/app/controllers/active_storage/representations/base_controller.rb +14 -0
  12. data/app/controllers/active_storage/representations/proxy_controller.rb +13 -0
  13. data/app/controllers/active_storage/{representations_controller.rb → representations/redirect_controller.rb} +3 -5
  14. data/app/controllers/concerns/active_storage/file_server.rb +18 -0
  15. data/app/controllers/concerns/active_storage/set_blob.rb +1 -1
  16. data/app/controllers/concerns/active_storage/set_current.rb +15 -0
  17. data/app/controllers/concerns/active_storage/set_headers.rb +12 -0
  18. data/app/javascript/activestorage/blob_record.js +7 -2
  19. data/app/jobs/active_storage/analyze_job.rb +5 -0
  20. data/app/jobs/active_storage/base_job.rb +0 -1
  21. data/app/jobs/active_storage/mirror_job.rb +15 -0
  22. data/app/jobs/active_storage/purge_job.rb +3 -0
  23. data/app/models/active_storage/attachment.rb +35 -16
  24. data/app/models/active_storage/blob/analyzable.rb +6 -2
  25. data/app/models/active_storage/blob/identifiable.rb +7 -6
  26. data/app/models/active_storage/blob/representable.rb +36 -6
  27. data/app/models/active_storage/blob.rb +186 -68
  28. data/app/models/active_storage/filename.rb +0 -6
  29. data/app/models/active_storage/preview.rb +37 -12
  30. data/app/models/active_storage/record.rb +7 -0
  31. data/app/models/active_storage/variant.rb +53 -67
  32. data/app/models/active_storage/variant_record.rb +8 -0
  33. data/app/models/active_storage/variant_with_record.rb +54 -0
  34. data/app/models/active_storage/variation.rb +30 -94
  35. data/config/routes.rb +66 -15
  36. data/db/migrate/20170806125915_create_active_storage_tables.rb +14 -5
  37. data/db/update_migrate/20190112182829_add_service_name_to_active_storage_blobs.rb +17 -0
  38. data/db/update_migrate/20191206030411_create_active_storage_variant_records.rb +11 -0
  39. data/lib/active_storage/analyzer/image_analyzer.rb +14 -4
  40. data/lib/active_storage/analyzer/null_analyzer.rb +4 -0
  41. data/lib/active_storage/analyzer/video_analyzer.rb +17 -8
  42. data/lib/active_storage/analyzer.rb +15 -4
  43. data/lib/active_storage/attached/changes/create_many.rb +47 -0
  44. data/lib/active_storage/attached/changes/create_one.rb +82 -0
  45. data/lib/active_storage/attached/changes/create_one_of_many.rb +10 -0
  46. data/lib/active_storage/attached/changes/delete_many.rb +27 -0
  47. data/lib/active_storage/attached/changes/delete_one.rb +19 -0
  48. data/lib/active_storage/attached/changes.rb +16 -0
  49. data/lib/active_storage/attached/many.rb +19 -12
  50. data/lib/active_storage/attached/model.rb +212 -0
  51. data/lib/active_storage/attached/one.rb +19 -21
  52. data/lib/active_storage/attached.rb +7 -22
  53. data/lib/active_storage/downloader.rb +43 -0
  54. data/lib/active_storage/engine.rb +60 -38
  55. data/lib/active_storage/errors.rb +25 -3
  56. data/lib/active_storage/gem_version.rb +4 -4
  57. data/lib/active_storage/log_subscriber.rb +6 -0
  58. data/lib/active_storage/previewer/mupdf_previewer.rb +3 -3
  59. data/lib/active_storage/previewer/poppler_pdf_previewer.rb +3 -3
  60. data/lib/active_storage/previewer/video_previewer.rb +17 -10
  61. data/lib/active_storage/previewer.rb +34 -14
  62. data/lib/active_storage/reflection.rb +64 -0
  63. data/lib/active_storage/service/azure_storage_service.rb +65 -44
  64. data/lib/active_storage/service/configurator.rb +6 -2
  65. data/lib/active_storage/service/disk_service.rb +57 -44
  66. data/lib/active_storage/service/gcs_service.rb +68 -64
  67. data/lib/active_storage/service/mirror_service.rb +31 -7
  68. data/lib/active_storage/service/registry.rb +32 -0
  69. data/lib/active_storage/service/s3_service.rb +56 -24
  70. data/lib/active_storage/service.rb +44 -12
  71. data/lib/active_storage/transformers/image_processing_transformer.rb +45 -0
  72. data/lib/active_storage/transformers/transformer.rb +39 -0
  73. data/lib/active_storage.rb +31 -296
  74. data/lib/tasks/activestorage.rake +11 -0
  75. metadata +82 -16
  76. data/app/models/active_storage/filename/parameters.rb +0 -36
  77. data/lib/active_storage/attached/macros.rb +0 -110
  78. data/lib/active_storage/downloading.rb +0 -39
@@ -9,21 +9,28 @@ module ActiveStorage
9
9
  # Wraps the Amazon Simple Storage Service (S3) as an Active Storage service.
10
10
  # See ActiveStorage::Service for the generic API documentation that applies to all services.
11
11
  class Service::S3Service < Service
12
- attr_reader :client, :bucket, :upload_options
12
+ attr_reader :client, :bucket
13
+ attr_reader :multipart_upload_threshold, :upload_options
13
14
 
14
- def initialize(bucket:, upload: {}, **options)
15
+ def initialize(bucket:, upload: {}, public: false, **options)
15
16
  @client = Aws::S3::Resource.new(**options)
16
17
  @bucket = @client.bucket(bucket)
17
18
 
19
+ @multipart_upload_threshold = upload.delete(:multipart_threshold) || 100.megabytes
20
+ @public = public
21
+
18
22
  @upload_options = upload
23
+ @upload_options[:acl] = "public-read" if public?
19
24
  end
20
25
 
21
- def upload(key, io, checksum: nil, **)
26
+ def upload(key, io, checksum: nil, filename: nil, content_type: nil, disposition: nil, **)
22
27
  instrument :upload, key: key, checksum: checksum do
23
- begin
24
- object_for(key).put(upload_options.merge(body: io, content_md5: checksum))
25
- rescue Aws::S3::Errors::BadDigest
26
- raise ActiveStorage::IntegrityError
28
+ content_disposition = content_disposition_with(filename: filename, type: disposition) if disposition && filename
29
+
30
+ if io.size < multipart_upload_threshold
31
+ upload_with_single_part key, io, checksum: checksum, content_type: content_type, content_disposition: content_disposition
32
+ else
33
+ upload_with_multipart key, io, content_type: content_type, content_disposition: content_disposition
27
34
  end
28
35
  end
29
36
  end
@@ -36,13 +43,17 @@ module ActiveStorage
36
43
  else
37
44
  instrument :download, key: key do
38
45
  object_for(key).get.body.string.force_encoding(Encoding::BINARY)
46
+ rescue Aws::S3::Errors::NoSuchKey
47
+ raise ActiveStorage::FileNotFoundError
39
48
  end
40
49
  end
41
50
  end
42
51
 
43
52
  def download_chunk(key, range)
44
53
  instrument :download_chunk, key: key, range: range do
45
- object_for(key).get(range: "bytes=#{range.begin}-#{range.exclude_end? ? range.end - 1 : range.end}").body.read.force_encoding(Encoding::BINARY)
54
+ object_for(key).get(range: "bytes=#{range.begin}-#{range.exclude_end? ? range.end - 1 : range.end}").body.string.force_encoding(Encoding::BINARY)
55
+ rescue Aws::S3::Errors::NoSuchKey
56
+ raise ActiveStorage::FileNotFoundError
46
57
  end
47
58
  end
48
59
 
@@ -66,23 +77,11 @@ module ActiveStorage
66
77
  end
67
78
  end
68
79
 
69
- def url(key, expires_in:, filename:, disposition:, content_type:)
70
- instrument :url, key: key do |payload|
71
- generated_url = object_for(key).presigned_url :get, expires_in: expires_in.to_i,
72
- response_content_disposition: content_disposition_with(type: disposition, filename: filename),
73
- response_content_type: content_type
74
-
75
- payload[:url] = generated_url
76
-
77
- generated_url
78
- end
79
- end
80
-
81
80
  def url_for_direct_upload(key, expires_in:, content_type:, content_length:, checksum:)
82
81
  instrument :url, key: key do |payload|
83
82
  generated_url = object_for(key).presigned_url :put, expires_in: expires_in.to_i,
84
83
  content_type: content_type, content_length: content_length, content_md5: checksum,
85
- whitelist_headers: ['content-length']
84
+ whitelist_headers: ["content-length"], **upload_options
86
85
 
87
86
  payload[:url] = generated_url
88
87
 
@@ -90,11 +89,42 @@ module ActiveStorage
90
89
  end
91
90
  end
92
91
 
93
- def headers_for_direct_upload(key, content_type:, checksum:, **)
94
- { "Content-Type" => content_type, "Content-MD5" => checksum }
92
+ def headers_for_direct_upload(key, content_type:, checksum:, filename: nil, disposition: nil, **)
93
+ content_disposition = content_disposition_with(type: disposition, filename: filename) if filename
94
+
95
+ { "Content-Type" => content_type, "Content-MD5" => checksum, "Content-Disposition" => content_disposition }
95
96
  end
96
97
 
97
98
  private
99
+ def private_url(key, expires_in:, filename:, disposition:, content_type:, **)
100
+ object_for(key).presigned_url :get, expires_in: expires_in.to_i,
101
+ response_content_disposition: content_disposition_with(type: disposition, filename: filename),
102
+ response_content_type: content_type
103
+ end
104
+
105
+ def public_url(key, **)
106
+ object_for(key).public_url
107
+ end
108
+
109
+
110
+ MAXIMUM_UPLOAD_PARTS_COUNT = 10000
111
+ MINIMUM_UPLOAD_PART_SIZE = 5.megabytes
112
+
113
+ def upload_with_single_part(key, io, checksum: nil, content_type: nil, content_disposition: nil)
114
+ object_for(key).put(body: io, content_md5: checksum, content_type: content_type, content_disposition: content_disposition, **upload_options)
115
+ rescue Aws::S3::Errors::BadDigest
116
+ raise ActiveStorage::IntegrityError
117
+ end
118
+
119
+ def upload_with_multipart(key, io, content_type: nil, content_disposition: nil)
120
+ part_size = [ io.size.fdiv(MAXIMUM_UPLOAD_PARTS_COUNT).ceil, MINIMUM_UPLOAD_PART_SIZE ].max
121
+
122
+ object_for(key).upload_stream(content_type: content_type, content_disposition: content_disposition, part_size: part_size, **upload_options) do |out|
123
+ IO.copy_stream(io, out)
124
+ end
125
+ end
126
+
127
+
98
128
  def object_for(key)
99
129
  bucket.object(key)
100
130
  end
@@ -106,8 +136,10 @@ module ActiveStorage
106
136
  chunk_size = 5.megabytes
107
137
  offset = 0
108
138
 
139
+ raise ActiveStorage::FileNotFoundError unless object.exists?
140
+
109
141
  while offset < object.content_length
110
- yield object.get(range: "bytes=#{offset}-#{offset + chunk_size - 1}").body.read.force_encoding(Encoding::BINARY)
142
+ yield object.get(range: "bytes=#{offset}-#{offset + chunk_size - 1}").body.string.force_encoding(Encoding::BINARY)
111
143
  offset += chunk_size
112
144
  end
113
145
  end
@@ -1,10 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_storage/log_subscriber"
4
+ require "active_storage/downloader"
5
+ require "action_dispatch"
6
+ require "action_dispatch/http/content_disposition"
4
7
 
5
8
  module ActiveStorage
6
- class IntegrityError < StandardError; end
7
-
8
9
  # Abstract class serving as an interface for concrete services.
9
10
  #
10
11
  # The available services are:
@@ -40,8 +41,7 @@ module ActiveStorage
40
41
  class Service
41
42
  extend ActiveSupport::Autoload
42
43
  autoload :Configurator
43
-
44
- class_attribute :url_expires_in, default: 5.minutes
44
+ attr_accessor :name
45
45
 
46
46
  class << self
47
47
  # Configure an Active Storage service by name from a set of configurations,
@@ -57,8 +57,10 @@ module ActiveStorage
57
57
  # Passes the configurator and all of the service's config as keyword args.
58
58
  #
59
59
  # See MirrorService for an example.
60
- def build(configurator:, service: nil, **service_config) #:nodoc:
61
- new(**service_config)
60
+ def build(configurator:, name:, service: nil, **service_config) #:nodoc:
61
+ new(**service_config).tap do |service_instance|
62
+ service_instance.name = name
63
+ end
62
64
  end
63
65
  end
64
66
 
@@ -84,6 +86,10 @@ module ActiveStorage
84
86
  raise NotImplementedError
85
87
  end
86
88
 
89
+ def open(*args, **options, &block)
90
+ ActiveStorage::Downloader.new(self).open(*args, **options, &block)
91
+ end
92
+
87
93
  # Delete the file at the +key+.
88
94
  def delete(key)
89
95
  raise NotImplementedError
@@ -99,11 +105,23 @@ module ActiveStorage
99
105
  raise NotImplementedError
100
106
  end
101
107
 
102
- # Returns a signed, temporary URL for the file at the +key+. The URL will be valid for the amount
103
- # of seconds specified in +expires_in+. You most also provide the +disposition+ (+:inline+ or +:attachment+),
104
- # +filename+, and +content_type+ that you wish the file to be served with on request.
105
- def url(key, expires_in:, disposition:, filename:, content_type:)
106
- raise NotImplementedError
108
+ # Returns the URL for the file at the +key+. This returns a permanent URL for public files, and returns a
109
+ # short-lived URL for private files. For private files you can provide the +disposition+ (+:inline+ or +:attachment+),
110
+ # +filename+, and +content_type+ that you wish the file to be served with on request. Additionally, you can also provide
111
+ # the amount of seconds the URL will be valid for, specified in +expires_in+.
112
+ def url(key, **options)
113
+ instrument :url, key: key do |payload|
114
+ generated_url =
115
+ if public?
116
+ public_url(key, **options)
117
+ else
118
+ private_url(key, **options)
119
+ end
120
+
121
+ payload[:url] = generated_url
122
+
123
+ generated_url
124
+ end
107
125
  end
108
126
 
109
127
  # Returns a signed, temporary URL that a direct upload file can be PUT to on the +key+.
@@ -119,7 +137,20 @@ module ActiveStorage
119
137
  {}
120
138
  end
121
139
 
140
+ def public?
141
+ @public
142
+ end
143
+
122
144
  private
145
+ def private_url(key, expires_in:, filename:, disposition:, content_type:, **)
146
+ raise NotImplementedError
147
+ end
148
+
149
+ def public_url(key, **)
150
+ raise NotImplementedError
151
+ end
152
+
153
+
123
154
  def instrument(operation, payload = {}, &block)
124
155
  ActiveSupport::Notifications.instrument(
125
156
  "service_#{operation}.active_storage",
@@ -132,7 +163,8 @@ module ActiveStorage
132
163
  end
133
164
 
134
165
  def content_disposition_with(type: "inline", filename:)
135
- (type.to_s.presence_in(%w( attachment inline )) || "inline") + "; #{filename.parameters}"
166
+ disposition = (type.to_s.presence_in(%w( attachment inline )) || "inline")
167
+ ActionDispatch::Http::ContentDisposition.format(disposition: disposition, filename: filename.sanitized)
136
168
  end
137
169
  end
138
170
  end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require "image_processing"
5
+ rescue LoadError
6
+ raise LoadError, <<~ERROR.squish
7
+ Generating image variants require the image_processing gem.
8
+ Please add `gem 'image_processing', '~> 1.2'` to your Gemfile.
9
+ ERROR
10
+ end
11
+
12
+ module ActiveStorage
13
+ module Transformers
14
+ class ImageProcessingTransformer < Transformer
15
+ private
16
+ def process(file, format:)
17
+ processor.
18
+ source(file).
19
+ loader(page: 0).
20
+ convert(format).
21
+ apply(operations).
22
+ call
23
+ end
24
+
25
+ def processor
26
+ ImageProcessing.const_get(ActiveStorage.variant_processor.to_s.camelize)
27
+ end
28
+
29
+ def operations
30
+ transformations.each_with_object([]) do |(name, argument), list|
31
+ if name.to_s == "combine_options"
32
+ raise ArgumentError, <<~ERROR.squish
33
+ Active Storage's ImageProcessing transformer doesn't support :combine_options,
34
+ as it always generates a single ImageMagick command.
35
+ ERROR
36
+ end
37
+
38
+ if argument.present?
39
+ list << [ name, argument ]
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveStorage
4
+ module Transformers
5
+ # A Transformer applies a set of transformations to an image.
6
+ #
7
+ # The following concrete subclasses are included in Active Storage:
8
+ #
9
+ # * ActiveStorage::Transformers::ImageProcessingTransformer:
10
+ # backed by ImageProcessing, a common interface for MiniMagick and ruby-vips
11
+ class Transformer
12
+ attr_reader :transformations
13
+
14
+ def initialize(transformations)
15
+ @transformations = transformations
16
+ end
17
+
18
+ # Applies the transformations to the source image in +file+, producing a target image in the
19
+ # specified +format+. Yields an open Tempfile containing the target image. Closes and unlinks
20
+ # the output tempfile after yielding to the given block. Returns the result of the block.
21
+ def transform(file, format:)
22
+ output = process(file, format: format)
23
+
24
+ begin
25
+ yield output
26
+ ensure
27
+ output.close!
28
+ end
29
+ end
30
+
31
+ private
32
+ # Returns an open Tempfile containing a transformed image in the given +format+.
33
+ # All subclasses implement this method.
34
+ def process(file, format:) #:doc:
35
+ raise NotImplementedError
36
+ end
37
+ end
38
+ end
39
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  #--
4
- # Copyright (c) 2017-2018 David Heinemeier Hansson, Basecamp
4
+ # Copyright (c) 2017-2020 David Heinemeier Hansson, Basecamp
5
5
  #
6
6
  # Permission is hereby granted, free of charge, to any person obtaining
7
7
  # a copy of this software and associated documentation files (the
@@ -26,6 +26,7 @@
26
26
  require "active_record"
27
27
  require "active_support"
28
28
  require "active_support/rails"
29
+ require "active_support/core_ext/numeric/time"
29
30
 
30
31
  require "active_storage/version"
31
32
  require "active_storage/errors"
@@ -42,302 +43,36 @@ module ActiveStorage
42
43
 
43
44
  mattr_accessor :logger
44
45
  mattr_accessor :verifier
45
- mattr_accessor :queue
46
+ mattr_accessor :variant_processor, default: :mini_magick
47
+
48
+ mattr_accessor :queues, default: {}
49
+
46
50
  mattr_accessor :previewers, default: []
47
- mattr_accessor :analyzers, default: []
51
+ mattr_accessor :analyzers, default: []
52
+
48
53
  mattr_accessor :paths, default: {}
49
- mattr_accessor :variable_content_types, default: []
54
+
55
+ mattr_accessor :variable_content_types, default: []
56
+ mattr_accessor :web_image_content_types, default: []
57
+ mattr_accessor :binary_content_type, default: "application/octet-stream"
50
58
  mattr_accessor :content_types_to_serve_as_binary, default: []
51
- mattr_accessor :content_types_allowed_inline, default: []
52
- mattr_accessor :binary_content_type, default: "application/octet-stream"
53
- mattr_accessor :supported_image_processing_methods, default: [
54
- "adaptive_blur",
55
- "adaptive_resize",
56
- "adaptive_sharpen",
57
- "adjoin",
58
- "affine",
59
- "alpha",
60
- "annotate",
61
- "antialias",
62
- "append",
63
- "apply",
64
- "attenuate",
65
- "authenticate",
66
- "auto_gamma",
67
- "auto_level",
68
- "auto_orient",
69
- "auto_threshold",
70
- "backdrop",
71
- "background",
72
- "bench",
73
- "bias",
74
- "bilateral_blur",
75
- "black_point_compensation",
76
- "black_threshold",
77
- "blend",
78
- "blue_primary",
79
- "blue_shift",
80
- "blur",
81
- "border",
82
- "bordercolor",
83
- "borderwidth",
84
- "brightness_contrast",
85
- "cache",
86
- "canny",
87
- "caption",
88
- "channel",
89
- "channel_fx",
90
- "charcoal",
91
- "chop",
92
- "clahe",
93
- "clamp",
94
- "clip",
95
- "clip_path",
96
- "clone",
97
- "clut",
98
- "coalesce",
99
- "colorize",
100
- "colormap",
101
- "color_matrix",
102
- "colors",
103
- "colorspace",
104
- "colourspace",
105
- "color_threshold",
106
- "combine",
107
- "combine_options",
108
- "comment",
109
- "compare",
110
- "complex",
111
- "compose",
112
- "composite",
113
- "compress",
114
- "connected_components",
115
- "contrast",
116
- "contrast_stretch",
117
- "convert",
118
- "convolve",
119
- "copy",
120
- "crop",
121
- "cycle",
122
- "deconstruct",
123
- "define",
124
- "delay",
125
- "delete",
126
- "density",
127
- "depth",
128
- "descend",
129
- "deskew",
130
- "despeckle",
131
- "direction",
132
- "displace",
133
- "dispose",
134
- "dissimilarity_threshold",
135
- "dissolve",
136
- "distort",
137
- "dither",
138
- "draw",
139
- "duplicate",
140
- "edge",
141
- "emboss",
142
- "encoding",
143
- "endian",
144
- "enhance",
145
- "equalize",
146
- "evaluate",
147
- "evaluate_sequence",
148
- "extent",
149
- "extract",
150
- "family",
151
- "features",
152
- "fft",
153
- "fill",
154
- "filter",
155
- "flatten",
156
- "flip",
157
- "floodfill",
158
- "flop",
159
- "font",
160
- "foreground",
161
- "format",
162
- "frame",
163
- "function",
164
- "fuzz",
165
- "fx",
166
- "gamma",
167
- "gaussian_blur",
168
- "geometry",
169
- "gravity",
170
- "grayscale",
171
- "green_primary",
172
- "hald_clut",
173
- "highlight_color",
174
- "hough_lines",
175
- "iconGeometry",
176
- "iconic",
177
- "identify",
178
- "ift",
179
- "illuminant",
180
- "immutable",
181
- "implode",
182
- "insert",
183
- "intensity",
184
- "intent",
185
- "interlace",
186
- "interline_spacing",
187
- "interpolate",
188
- "interpolative_resize",
189
- "interword_spacing",
190
- "kerning",
191
- "kmeans",
192
- "kuwahara",
193
- "label",
194
- "lat",
195
- "layers",
196
- "level",
197
- "level_colors",
198
- "limit",
199
- "limits",
200
- "linear_stretch",
201
- "linewidth",
202
- "liquid_rescale",
203
- "list",
204
- "loader",
205
- "log",
206
- "loop",
207
- "lowlight_color",
208
- "magnify",
209
- "map",
210
- "mattecolor",
211
- "median",
212
- "mean_shift",
213
- "metric",
214
- "mode",
215
- "modulate",
216
- "moments",
217
- "monitor",
218
- "monochrome",
219
- "morph",
220
- "morphology",
221
- "mosaic",
222
- "motion_blur",
223
- "name",
224
- "negate",
225
- "noise",
226
- "normalize",
227
- "opaque",
228
- "ordered_dither",
229
- "orient",
230
- "page",
231
- "paint",
232
- "pause",
233
- "perceptible",
234
- "ping",
235
- "pointsize",
236
- "polaroid",
237
- "poly",
238
- "posterize",
239
- "precision",
240
- "preview",
241
- "process",
242
- "quality",
243
- "quantize",
244
- "quiet",
245
- "radial_blur",
246
- "raise",
247
- "random_threshold",
248
- "range_threshold",
249
- "red_primary",
250
- "regard_warnings",
251
- "region",
252
- "remote",
253
- "render",
254
- "repage",
255
- "resample",
256
- "resize",
257
- "resize_to_fill",
258
- "resize_to_fit",
259
- "resize_to_limit",
260
- "resize_and_pad",
261
- "respect_parentheses",
262
- "reverse",
263
- "roll",
264
- "rotate",
265
- "sample",
266
- "sampling_factor",
267
- "saver",
268
- "scale",
269
- "scene",
270
- "screen",
271
- "seed",
272
- "segment",
273
- "selective_blur",
274
- "separate",
275
- "sepia_tone",
276
- "shade",
277
- "shadow",
278
- "shared_memory",
279
- "sharpen",
280
- "shave",
281
- "shear",
282
- "sigmoidal_contrast",
283
- "silent",
284
- "similarity_threshold",
285
- "size",
286
- "sketch",
287
- "smush",
288
- "snaps",
289
- "solarize",
290
- "sort_pixels",
291
- "sparse_color",
292
- "splice",
293
- "spread",
294
- "statistic",
295
- "stegano",
296
- "stereo",
297
- "storage_type",
298
- "stretch",
299
- "strip",
300
- "stroke",
301
- "strokewidth",
302
- "style",
303
- "subimage_search",
304
- "swap",
305
- "swirl",
306
- "synchronize",
307
- "taint",
308
- "text_font",
309
- "threshold",
310
- "thumbnail",
311
- "tile_offset",
312
- "tint",
313
- "title",
314
- "transform",
315
- "transparent",
316
- "transparent_color",
317
- "transpose",
318
- "transverse",
319
- "treedepth",
320
- "trim",
321
- "type",
322
- "undercolor",
323
- "unique_colors",
324
- "units",
325
- "unsharp",
326
- "update",
327
- "valid_image",
328
- "view",
329
- "vignette",
330
- "virtual_pixel",
331
- "visual",
332
- "watermark",
333
- "wave",
334
- "wavelet_denoise",
335
- "weight",
336
- "white_balance",
337
- "white_point",
338
- "white_threshold",
339
- "window",
340
- "window_group",
341
- ]
342
- mattr_accessor :unsupported_image_processing_arguments
59
+ mattr_accessor :content_types_allowed_inline, default: []
60
+
61
+ mattr_accessor :service_urls_expire_in, default: 5.minutes
62
+
63
+ mattr_accessor :routes_prefix, default: "/rails/active_storage"
64
+ mattr_accessor :draw_routes, default: true
65
+ mattr_accessor :resolve_model_to_route, default: :rails_storage_redirect
66
+
67
+ mattr_accessor :replace_on_assign_to_many, default: false
68
+ mattr_accessor :track_variants, default: false
69
+
70
+ mattr_accessor :video_preview_arguments, default: "-y -vframes 1 -f image2"
71
+
72
+ module Transformers
73
+ extend ActiveSupport::Autoload
74
+
75
+ autoload :Transformer
76
+ autoload :ImageProcessingTransformer
77
+ end
343
78
  end
@@ -12,4 +12,15 @@ namespace :active_storage do
12
12
  Rake::Task["app:active_storage:install:migrations"].invoke
13
13
  end
14
14
  end
15
+
16
+ # desc "Copy over the migrations needed to the application upgrading"
17
+ task update: :environment do
18
+ ENV["MIGRATIONS_PATH"] = "db/update_migrate"
19
+
20
+ if Rake::Task.task_defined?("active_storage:install")
21
+ Rake::Task["active_storage:install"].invoke
22
+ else
23
+ Rake::Task["app:active_storage:install"].invoke
24
+ end
25
+ end
15
26
  end