dynamic_image 3.0.8 → 3.1.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/README.md +393 -67
- data/Rakefile +3 -0
- data/app/models/dynamic_image/variant.rb +10 -0
- data/lib/dynamic_image/backfill.rb +85 -0
- data/lib/dynamic_image/belongs_to.rb +22 -0
- data/lib/dynamic_image/breakpoints.rb +93 -0
- data/lib/dynamic_image/controller.rb +57 -12
- data/lib/dynamic_image/digest_verifier.rb +20 -9
- data/lib/dynamic_image/engine.rb +4 -1
- data/lib/dynamic_image/errors.rb +30 -0
- data/lib/dynamic_image/format.rb +149 -8
- data/lib/dynamic_image/format_negotiator.rb +84 -0
- data/lib/dynamic_image/helper/formats.rb +57 -0
- data/lib/dynamic_image/helper/pictures.rb +124 -0
- data/lib/dynamic_image/helper.rb +100 -60
- data/lib/dynamic_image/image_processor/colors.rb +3 -7
- data/lib/dynamic_image/image_processor/frames.rb +10 -1
- data/lib/dynamic_image/image_processor/transform.rb +17 -2
- data/lib/dynamic_image/image_processor.rb +33 -6
- data/lib/dynamic_image/image_reader.rb +19 -1
- data/lib/dynamic_image/image_sizing.rb +51 -19
- data/lib/dynamic_image/metadata.rb +56 -5
- data/lib/dynamic_image/model/dimensions.rb +32 -13
- data/lib/dynamic_image/model/transformations.rb +50 -12
- data/lib/dynamic_image/model/validations.rb +15 -8
- data/lib/dynamic_image/model/variants.rb +6 -3
- data/lib/dynamic_image/model.rb +64 -35
- data/lib/dynamic_image/picture/format_policy.rb +72 -0
- data/lib/dynamic_image/picture.rb +215 -0
- data/lib/dynamic_image/processed_image.rb +53 -17
- data/lib/dynamic_image/ratio.rb +43 -0
- data/lib/dynamic_image/routing.rb +14 -3
- data/lib/dynamic_image/schema.rb +47 -0
- data/lib/dynamic_image/version.rb +1 -1
- data/lib/dynamic_image.rb +61 -1
- data/lib/rails/generators/dynamic_image/resource/USAGE +17 -0
- data/lib/rails/generators/dynamic_image/resource/resource_generator.rb +57 -21
- data/lib/rails/generators/dynamic_image/resource/templates/create_table_migration.rb.tt +32 -0
- data/lib/rails/generators/dynamic_image/upgrade/USAGE +17 -0
- data/lib/rails/generators/dynamic_image/upgrade/templates/upgrade_migration.rb.tt +10 -0
- data/lib/rails/generators/dynamic_image/upgrade/upgrade_generator.rb +111 -0
- data/lib/tasks/dynamic_image.rake +25 -0
- metadata +26 -15
- data/lib/dynamic_image/jobs/create_variant.rb +0 -22
- data/lib/dynamic_image/jobs.rb +0 -3
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DynamicImage
|
|
4
|
+
# = DynamicImage Schema
|
|
5
|
+
#
|
|
6
|
+
# The database schema {DynamicImage::Model} expects on the table holding the image.
|
|
7
|
+
#
|
|
8
|
+
# DynamicImage doesn't own that table. Unlike +dynamic_image_variants+, which has a fixed name and an engine
|
|
9
|
+
# migration, the image table is created in the application by the +dynamic_image:resource+ generator, under
|
|
10
|
+
# whatever name the application picked, and there may be more than one. This is the single definition of what it
|
|
11
|
+
# should contain.
|
|
12
|
+
#
|
|
13
|
+
# @see DynamicImage::Model
|
|
14
|
+
module Schema
|
|
15
|
+
# The expected columns, in the order they should appear in a migration. Each is described by its migration type
|
|
16
|
+
# and whether it accepts +NULL+.
|
|
17
|
+
#
|
|
18
|
+
# +frame_count+ and +alpha+ are nullable. NULL means the image predates them being recorded, which is not the
|
|
19
|
+
# same as knowing the image is a still or opaque.
|
|
20
|
+
#
|
|
21
|
+
# @return [Hash{Symbol => Hash}]
|
|
22
|
+
ATTRIBUTES = {
|
|
23
|
+
content_hash: { type: :string, null: false },
|
|
24
|
+
content_type: { type: :string, null: false },
|
|
25
|
+
content_length: { type: :integer, null: false },
|
|
26
|
+
filename: { type: :string, null: false },
|
|
27
|
+
colorspace: { type: :string, null: false },
|
|
28
|
+
real_width: { type: :integer, null: false },
|
|
29
|
+
real_height: { type: :integer, null: false },
|
|
30
|
+
frame_count: { type: :integer, null: true },
|
|
31
|
+
alpha: { type: :boolean, null: true },
|
|
32
|
+
crop_width: { type: :integer, null: true },
|
|
33
|
+
crop_height: { type: :integer, null: true },
|
|
34
|
+
crop_start_x: { type: :integer, null: true },
|
|
35
|
+
crop_start_y: { type: :integer, null: true },
|
|
36
|
+
crop_gravity_x: { type: :integer, null: true },
|
|
37
|
+
crop_gravity_y: { type: :integer, null: true }
|
|
38
|
+
}.freeze
|
|
39
|
+
|
|
40
|
+
# The expected indexes.
|
|
41
|
+
#
|
|
42
|
+
# @return [Array<Hash>]
|
|
43
|
+
INDEXES = [
|
|
44
|
+
{ columns: %i[content_hash], unique: false }
|
|
45
|
+
].freeze
|
|
46
|
+
end
|
|
47
|
+
end
|
data/lib/dynamic_image.rb
CHANGED
|
@@ -4,22 +4,82 @@ require "dis"
|
|
|
4
4
|
require "vector2d"
|
|
5
5
|
require "vips"
|
|
6
6
|
|
|
7
|
+
require "dynamic_image/backfill"
|
|
7
8
|
require "dynamic_image/belongs_to"
|
|
9
|
+
require "dynamic_image/breakpoints"
|
|
8
10
|
require "dynamic_image/controller"
|
|
9
11
|
require "dynamic_image/digest_verifier"
|
|
10
12
|
require "dynamic_image/engine"
|
|
11
13
|
require "dynamic_image/errors"
|
|
12
14
|
require "dynamic_image/format"
|
|
15
|
+
require "dynamic_image/format_negotiator"
|
|
13
16
|
require "dynamic_image/helper"
|
|
14
17
|
require "dynamic_image/image_processor"
|
|
15
18
|
require "dynamic_image/image_reader"
|
|
16
19
|
require "dynamic_image/image_sizing"
|
|
17
|
-
require "dynamic_image/jobs"
|
|
18
20
|
require "dynamic_image/metadata"
|
|
19
21
|
require "dynamic_image/model"
|
|
22
|
+
require "dynamic_image/picture"
|
|
23
|
+
require "dynamic_image/picture/format_policy"
|
|
20
24
|
require "dynamic_image/processed_image"
|
|
25
|
+
require "dynamic_image/ratio"
|
|
21
26
|
require "dynamic_image/routing"
|
|
27
|
+
require "dynamic_image/schema"
|
|
22
28
|
|
|
29
|
+
# A Rails engine for image uploads. Rather than creating a pre-defined set of images when a file is uploaded, it
|
|
30
|
+
# stores the original file and generates images on demand. It handles cropping, resizing, format and colorspace
|
|
31
|
+
# conversion, and stores each processed size as a variant.
|
|
32
|
+
#
|
|
33
|
+
# Include {DynamicImage::Model} in the model holding the image and {DynamicImage::Controller} in the controller
|
|
34
|
+
# serving it, then declare the routes with {DynamicImage::Routing#image_resources}. Views render images through the
|
|
35
|
+
# helpers in {DynamicImage::Helper}, which sign the URLs.
|
|
36
|
+
#
|
|
37
|
+
# Files are stored with Dis, and processing is done with libvips.
|
|
38
|
+
#
|
|
39
|
+
# @see DynamicImage::Model
|
|
40
|
+
# @see DynamicImage::Controller
|
|
41
|
+
# @see DynamicImage::Helper
|
|
42
|
+
# @see DynamicImage::ImageSizing
|
|
43
|
+
# @see DynamicImage::ProcessedImage
|
|
23
44
|
module DynamicImage
|
|
45
|
+
# The formats anything that renders images will understand. Fallback images in a <tt>picture</tt> are negotiated
|
|
46
|
+
# from this list, and it is the default for {DynamicImage.mailer_formats}.
|
|
47
|
+
#
|
|
48
|
+
# @return [Array<Symbol>] the format names, most preferred first
|
|
49
|
+
COMPATIBLE_FORMATS = %i[jpeg png gif].freeze
|
|
50
|
+
|
|
51
|
+
# Verifies the HMAC digests embedded in image URLs. Set by the engine from the application's key generator, which
|
|
52
|
+
# derives it from <tt>secret_key_base</tt>.
|
|
53
|
+
#
|
|
54
|
+
# @return [DynamicImage::DigestVerifier]
|
|
24
55
|
cattr_accessor :digest_verifier
|
|
56
|
+
|
|
57
|
+
# The formats a view accepts when it doesn't pass <tt>format:</tt>. Also decides what
|
|
58
|
+
# {DynamicImage::Model#safe_content_type} considers safe.
|
|
59
|
+
#
|
|
60
|
+
# @return [Array<Symbol>] the format names, most preferred first
|
|
61
|
+
mattr_accessor :default_formats, default: %i[jpeg png gif webp]
|
|
62
|
+
|
|
63
|
+
# The formats a mailer view accepts when it doesn't pass <tt>format:</tt>.
|
|
64
|
+
#
|
|
65
|
+
# @return [Array<Symbol>] the format names, most preferred first
|
|
66
|
+
mattr_accessor :mailer_formats, default: COMPATIBLE_FORMATS
|
|
67
|
+
|
|
68
|
+
# The breakpoints responsive images are rendered at. This can be a range, an array of explicit widths, or a single
|
|
69
|
+
# width.
|
|
70
|
+
#
|
|
71
|
+
# @return [Range, Array<Integer>, Integer]
|
|
72
|
+
# @see DynamicImage::Breakpoints
|
|
73
|
+
mattr_accessor :default_breakpoints, default: 320..3200
|
|
74
|
+
|
|
75
|
+
# The ratio between two breakpoints. Lower means a closer fit to what the browser needs, at the price of more
|
|
76
|
+
# variants to generate and store.
|
|
77
|
+
#
|
|
78
|
+
# @return [Float]
|
|
79
|
+
mattr_accessor :breakpoint_step, default: 1.4
|
|
80
|
+
|
|
81
|
+
# The width of the fallback image in a <tt>picture</tt> element.
|
|
82
|
+
#
|
|
83
|
+
# @return [Integer]
|
|
84
|
+
mattr_accessor :picture_fallback_width, default: 1200
|
|
25
85
|
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Description:
|
|
2
|
+
Creates a DynamicImage resource: a model including
|
|
3
|
+
DynamicImage::Model, a controller including DynamicImage::Controller,
|
|
4
|
+
a migration with the columns DynamicImage needs, and an
|
|
5
|
+
image_resources route.
|
|
6
|
+
|
|
7
|
+
Additional attributes are passed through to the migration, so a
|
|
8
|
+
resource can carry fields of its own.
|
|
9
|
+
|
|
10
|
+
Example:
|
|
11
|
+
bin/rails generate dynamic_image:resource image
|
|
12
|
+
|
|
13
|
+
creates an Image model, an ImagesController and a migration.
|
|
14
|
+
|
|
15
|
+
bin/rails generate dynamic_image:resource photo caption:string
|
|
16
|
+
|
|
17
|
+
adds a caption column to the migration.
|
|
@@ -2,22 +2,60 @@
|
|
|
2
2
|
|
|
3
3
|
require "rails/generators"
|
|
4
4
|
require "rails/generators/rails/resource/resource_generator"
|
|
5
|
+
require "rails/generators/active_record/migration"
|
|
6
|
+
|
|
7
|
+
require "dynamic_image/schema"
|
|
5
8
|
|
|
6
9
|
module DynamicImage
|
|
10
|
+
# Generators for setting up DynamicImage in an application.
|
|
7
11
|
module Generators
|
|
12
|
+
# Creates a DynamicImage resource: a model including {DynamicImage::Model}, a controller including
|
|
13
|
+
# {DynamicImage::Controller}, a migration with the columns DynamicImage needs, and an +image_resources+ route.
|
|
14
|
+
#
|
|
15
|
+
# bin/rails generate dynamic_image:resource image
|
|
16
|
+
#
|
|
17
|
+
# Additional attributes are passed through to the migration, letting a resource carry fields of its own.
|
|
18
|
+
#
|
|
19
|
+
# bin/rails generate dynamic_image:resource photo caption:string
|
|
20
|
+
#
|
|
21
|
+
# The migration is rendered from {DynamicImage::Schema}. The Active Record generator can't express nullability
|
|
22
|
+
# or indexes through its +name:type+ arguments.
|
|
8
23
|
class ResourceGenerator < Rails::Generators::ResourceGenerator
|
|
9
|
-
|
|
24
|
+
include ActiveRecord::Generators::Migration
|
|
25
|
+
|
|
26
|
+
source_root File.expand_path("templates", __dir__)
|
|
10
27
|
|
|
11
28
|
def initialize(args, *options)
|
|
12
|
-
|
|
29
|
+
@orm_args = args
|
|
30
|
+
super
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
no_commands do
|
|
34
|
+
# Thor consumes the raw arguments while parsing, so {#initialize} keeps a copy for the ORM generator.
|
|
35
|
+
def invoke_orm_generator(orm)
|
|
36
|
+
invoke(orm, @orm_args, options.merge("migration" => false))
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# The ORM generator would write its own migration, which can't carry nullability or indexes. Invoke it with
|
|
41
|
+
# +migration: false+ and render {#create_dynamic_image_migration} instead.
|
|
42
|
+
hook_for :orm, required: true, in: :rails, as: :model do |instance, orm|
|
|
43
|
+
instance.invoke_orm_generator(orm)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def create_dynamic_image_migration
|
|
47
|
+
migration_template(
|
|
48
|
+
"create_table_migration.rb",
|
|
49
|
+
File.join(db_migrate_path, "create_#{table_name}.rb")
|
|
50
|
+
)
|
|
13
51
|
end
|
|
14
52
|
|
|
15
53
|
def add_controller_extension
|
|
16
|
-
|
|
54
|
+
inject_into_class(
|
|
17
55
|
File.join("app/controllers",
|
|
18
56
|
class_path,
|
|
19
57
|
"#{file_name.pluralize}_controller.rb"),
|
|
20
|
-
|
|
58
|
+
"#{class_name.pluralize}Controller"
|
|
21
59
|
) do
|
|
22
60
|
" include DynamicImage::Controller\n\n private\n\n " \
|
|
23
61
|
"def model\n #{class_name}\n end\n"
|
|
@@ -25,9 +63,9 @@ module DynamicImage
|
|
|
25
63
|
end
|
|
26
64
|
|
|
27
65
|
def add_model_extension
|
|
28
|
-
|
|
66
|
+
inject_into_class(
|
|
29
67
|
File.join("app/models", class_path, "#{file_name}.rb"),
|
|
30
|
-
|
|
68
|
+
class_name
|
|
31
69
|
) do
|
|
32
70
|
" include DynamicImage::Model\n"
|
|
33
71
|
end
|
|
@@ -43,23 +81,21 @@ module DynamicImage
|
|
|
43
81
|
|
|
44
82
|
private
|
|
45
83
|
|
|
46
|
-
def
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
84
|
+
def schema_attributes
|
|
85
|
+
DynamicImage::Schema::ATTRIBUTES
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def schema_indexes
|
|
89
|
+
DynamicImage::Schema::INDEXES
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def index_columns(index)
|
|
93
|
+
columns = index[:columns]
|
|
94
|
+
columns.length == 1 ? columns.first.inspect : columns.inspect
|
|
52
95
|
end
|
|
53
96
|
|
|
54
|
-
def
|
|
55
|
-
|
|
56
|
-
content_length:integer
|
|
57
|
-
filename:string
|
|
58
|
-
colorspace:string
|
|
59
|
-
real_width:integer real_height:integer
|
|
60
|
-
crop_width:integer crop_height:integer
|
|
61
|
-
crop_start_x:integer crop_start_y:integer
|
|
62
|
-
crop_gravity_x:integer crop_gravity_y:integer]
|
|
97
|
+
def attributes_with_index
|
|
98
|
+
attributes.select { |a| !a.reference? && a.has_index? }
|
|
63
99
|
end
|
|
64
100
|
end
|
|
65
101
|
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
|
|
2
|
+
def change
|
|
3
|
+
create_table :<%= table_name %><%= primary_key_type %> do |t|
|
|
4
|
+
<% schema_attributes.each do |name, column| -%>
|
|
5
|
+
t.<%= column[:type] %> :<%= name %><%= ", null: false" unless column[:null] %>
|
|
6
|
+
<% end -%>
|
|
7
|
+
<% attributes.each do |attribute| -%>
|
|
8
|
+
<% if attribute.password_digest? -%>
|
|
9
|
+
t.string :password_digest<%= attribute.inject_options %>
|
|
10
|
+
<% elsif attribute.token? -%>
|
|
11
|
+
t.string :<%= attribute.name %><%= attribute.inject_options %>
|
|
12
|
+
<% elsif attribute.reference? -%>
|
|
13
|
+
t.<%= attribute.type %> :<%= attribute.name %><%= attribute.inject_options %><%= foreign_key_type %>
|
|
14
|
+
<% elsif !attribute.virtual? -%>
|
|
15
|
+
t.<%= attribute.type %> :<%= attribute.name %><%= attribute.inject_options %>
|
|
16
|
+
<% end -%>
|
|
17
|
+
<% end -%>
|
|
18
|
+
|
|
19
|
+
t.timestamps
|
|
20
|
+
end
|
|
21
|
+
<% schema_indexes.each do |index| -%>
|
|
22
|
+
|
|
23
|
+
add_index :<%= table_name %>, <%= index_columns(index) %><%= ", unique: true" if index[:unique] %>
|
|
24
|
+
<% end -%>
|
|
25
|
+
<% attributes.select(&:token?).each do |attribute| -%>
|
|
26
|
+
add_index :<%= table_name %>, :<%= attribute.index_name %><%= attribute.inject_index_options %>, unique: true
|
|
27
|
+
<% end -%>
|
|
28
|
+
<% attributes_with_index.each do |attribute| -%>
|
|
29
|
+
add_index :<%= table_name %>, :<%= attribute.index_name %><%= attribute.inject_index_options %>
|
|
30
|
+
<% end -%>
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Description:
|
|
2
|
+
Brings an existing DynamicImage table up to date with the schema the
|
|
3
|
+
installed version of the gem expects. Compares the table against
|
|
4
|
+
DynamicImage::Schema and writes a migration containing only what is
|
|
5
|
+
missing. If nothing is missing, no migration is written.
|
|
6
|
+
|
|
7
|
+
Only additive changes are generated. Columns are added nullable, and
|
|
8
|
+
columns whose nullability differs from the expected schema are
|
|
9
|
+
reported rather than altered: change_column_null fails on existing
|
|
10
|
+
NULLs, and only you can know whether the data allows it.
|
|
11
|
+
|
|
12
|
+
Run it once per DynamicImage model.
|
|
13
|
+
|
|
14
|
+
Example:
|
|
15
|
+
bin/rails generate dynamic_image:upgrade Image
|
|
16
|
+
|
|
17
|
+
creates db/migrate/XXX_add_frame_count_and_alpha_to_images.rb
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
|
|
2
|
+
def change
|
|
3
|
+
<% missing_columns.each do |name, column| -%>
|
|
4
|
+
add_column :<%= table_name %>, :<%= name %>, :<%= column[:type] %>
|
|
5
|
+
<% end -%>
|
|
6
|
+
<% missing_indexes.each do |index| -%>
|
|
7
|
+
add_index :<%= table_name %>, <%= index_columns(index) %><%= ", unique: true" if index[:unique] %>
|
|
8
|
+
<% end -%>
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators"
|
|
4
|
+
require "rails/generators/named_base"
|
|
5
|
+
require "rails/generators/active_record/migration"
|
|
6
|
+
|
|
7
|
+
require "dynamic_image/schema"
|
|
8
|
+
|
|
9
|
+
module DynamicImage
|
|
10
|
+
module Generators
|
|
11
|
+
# Brings an existing table up to date with {DynamicImage::Schema}.
|
|
12
|
+
#
|
|
13
|
+
# bin/rails generate dynamic_image:upgrade Image
|
|
14
|
+
#
|
|
15
|
+
# The migration is derived from the difference between the table and the schema, so running the generator
|
|
16
|
+
# again once the migration has been applied writes nothing. An application several releases behind gets a single
|
|
17
|
+
# migration with everything it's missing.
|
|
18
|
+
#
|
|
19
|
+
# Only additive changes are generated. Columns are added nullable, and nullability differences are reported
|
|
20
|
+
# instead of altered: +change_column_null+ fails on existing NULLs, and the generator can't know whether the
|
|
21
|
+
# data allows it.
|
|
22
|
+
class UpgradeGenerator < Rails::Generators::NamedBase
|
|
23
|
+
include ActiveRecord::Generators::Migration
|
|
24
|
+
|
|
25
|
+
source_root File.expand_path("templates", __dir__)
|
|
26
|
+
|
|
27
|
+
def create_upgrade_migration
|
|
28
|
+
if missing_columns.empty? && missing_indexes.empty?
|
|
29
|
+
say_status(:identical, "#{table_name} is up to date", :blue)
|
|
30
|
+
return
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
migration_template("upgrade_migration.rb",
|
|
34
|
+
File.join(db_migrate_path, "#{migration_name}.rb"))
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def report_nullability
|
|
38
|
+
nullable_in_table.each do |name|
|
|
39
|
+
say_status(:warn,
|
|
40
|
+
"#{table_name}.#{name} should be NOT NULL",
|
|
41
|
+
:yellow)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def report_index_locking
|
|
46
|
+
return if missing_indexes.empty?
|
|
47
|
+
|
|
48
|
+
say_status(:warn,
|
|
49
|
+
"adding an index locks the table while it builds",
|
|
50
|
+
:yellow)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
def model_class
|
|
56
|
+
@model_class ||= class_name.constantize
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def table_name
|
|
60
|
+
model_class.table_name
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def existing_columns
|
|
64
|
+
@existing_columns ||= model_class.columns.index_by { |c| c.name.to_sym }
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def existing_indexes
|
|
68
|
+
@existing_indexes ||=
|
|
69
|
+
model_class.connection.indexes(table_name).map do |index|
|
|
70
|
+
Array(index.columns).map(&:to_sym)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def missing_columns
|
|
75
|
+
@missing_columns ||=
|
|
76
|
+
DynamicImage::Schema::ATTRIBUTES.reject do |name, _|
|
|
77
|
+
existing_columns.key?(name)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# An index whose leading columns match already answers the query, so only a missing prefix counts as missing.
|
|
82
|
+
def missing_indexes
|
|
83
|
+
@missing_indexes ||=
|
|
84
|
+
DynamicImage::Schema::INDEXES.reject do |index|
|
|
85
|
+
columns = index[:columns]
|
|
86
|
+
existing_indexes.any? { |e| e.first(columns.length) == columns }
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def nullable_in_table
|
|
91
|
+
DynamicImage::Schema::ATTRIBUTES.filter_map do |name, column|
|
|
92
|
+
existing = existing_columns[name]
|
|
93
|
+
name if existing && !column[:null] && existing.null
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def index_columns(index)
|
|
98
|
+
columns = index[:columns]
|
|
99
|
+
columns.length == 1 ? columns.first.inspect : columns.inspect
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def migration_name
|
|
103
|
+
if missing_columns.any?
|
|
104
|
+
"add_#{missing_columns.keys.join('_and_')}_to_#{table_name}"
|
|
105
|
+
else
|
|
106
|
+
"add_dynamic_image_indexes_to_#{table_name}"
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
namespace :dynamic_image do
|
|
4
|
+
desc "Fill in metadata columns for images stored before they existed"
|
|
5
|
+
task backfill: :environment do
|
|
6
|
+
unless ENV["MODELS"]
|
|
7
|
+
puts "Usage: #{$PROGRAM_NAME} dynamic_image:backfill MODELS=Image"
|
|
8
|
+
exit
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
ENV["MODELS"].split(",").map(&:strip).map(&:constantize).each do |model|
|
|
12
|
+
backfill = DynamicImage::Backfill.new(model)
|
|
13
|
+
total = backfill.pending.count
|
|
14
|
+
puts "#{model.name}: #{total} #{'record'.pluralize(total)} to read"
|
|
15
|
+
|
|
16
|
+
processed = 0
|
|
17
|
+
backfill.run do
|
|
18
|
+
processed += 1
|
|
19
|
+
print("\r #{processed}/#{total}") if (processed % 10).zero?
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
puts "\r #{backfill.updated} updated, #{backfill.skipped} skipped"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dynamic_image
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.0
|
|
4
|
+
version: 3.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Inge Jørgensen
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - "~>"
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: '1
|
|
18
|
+
version: '2.1'
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - "~>"
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: '1
|
|
25
|
+
version: '2.1'
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: rails
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -63,20 +63,14 @@ dependencies:
|
|
|
63
63
|
requirements:
|
|
64
64
|
- - "~>"
|
|
65
65
|
- !ruby/object:Gem::Version
|
|
66
|
-
version: '2.
|
|
67
|
-
- - ">="
|
|
68
|
-
- !ruby/object:Gem::Version
|
|
69
|
-
version: 2.2.1
|
|
66
|
+
version: '2.3'
|
|
70
67
|
type: :runtime
|
|
71
68
|
prerelease: false
|
|
72
69
|
version_requirements: !ruby/object:Gem::Requirement
|
|
73
70
|
requirements:
|
|
74
71
|
- - "~>"
|
|
75
72
|
- !ruby/object:Gem::Version
|
|
76
|
-
version: '2.
|
|
77
|
-
- - ">="
|
|
78
|
-
- !ruby/object:Gem::Version
|
|
79
|
-
version: 2.2.1
|
|
73
|
+
version: '2.3'
|
|
80
74
|
description: DynamicImage is a Rails plugin that simplifies image uploading and processing
|
|
81
75
|
email:
|
|
82
76
|
- inge@elektronaut.no
|
|
@@ -91,36 +85,53 @@ files:
|
|
|
91
85
|
- app/views/dynamic_image/images/show.html.erb
|
|
92
86
|
- db/migrate/20190620160500_create_dynamic_image_variants.rb
|
|
93
87
|
- lib/dynamic_image.rb
|
|
88
|
+
- lib/dynamic_image/backfill.rb
|
|
94
89
|
- lib/dynamic_image/belongs_to.rb
|
|
90
|
+
- lib/dynamic_image/breakpoints.rb
|
|
95
91
|
- lib/dynamic_image/controller.rb
|
|
96
92
|
- lib/dynamic_image/digest_verifier.rb
|
|
97
93
|
- lib/dynamic_image/engine.rb
|
|
98
94
|
- lib/dynamic_image/errors.rb
|
|
99
95
|
- lib/dynamic_image/format.rb
|
|
96
|
+
- lib/dynamic_image/format_negotiator.rb
|
|
100
97
|
- lib/dynamic_image/helper.rb
|
|
98
|
+
- lib/dynamic_image/helper/formats.rb
|
|
99
|
+
- lib/dynamic_image/helper/pictures.rb
|
|
101
100
|
- lib/dynamic_image/image_processor.rb
|
|
102
101
|
- lib/dynamic_image/image_processor/colors.rb
|
|
103
102
|
- lib/dynamic_image/image_processor/frames.rb
|
|
104
103
|
- lib/dynamic_image/image_processor/transform.rb
|
|
105
104
|
- lib/dynamic_image/image_reader.rb
|
|
106
105
|
- lib/dynamic_image/image_sizing.rb
|
|
107
|
-
- lib/dynamic_image/jobs.rb
|
|
108
|
-
- lib/dynamic_image/jobs/create_variant.rb
|
|
109
106
|
- lib/dynamic_image/metadata.rb
|
|
110
107
|
- lib/dynamic_image/model.rb
|
|
111
108
|
- lib/dynamic_image/model/dimensions.rb
|
|
112
109
|
- lib/dynamic_image/model/transformations.rb
|
|
113
110
|
- lib/dynamic_image/model/validations.rb
|
|
114
111
|
- lib/dynamic_image/model/variants.rb
|
|
112
|
+
- lib/dynamic_image/picture.rb
|
|
113
|
+
- lib/dynamic_image/picture/format_policy.rb
|
|
115
114
|
- lib/dynamic_image/processed_image.rb
|
|
115
|
+
- lib/dynamic_image/ratio.rb
|
|
116
116
|
- lib/dynamic_image/routing.rb
|
|
117
|
+
- lib/dynamic_image/schema.rb
|
|
117
118
|
- lib/dynamic_image/version.rb
|
|
119
|
+
- lib/rails/generators/dynamic_image/resource/USAGE
|
|
118
120
|
- lib/rails/generators/dynamic_image/resource/resource_generator.rb
|
|
121
|
+
- lib/rails/generators/dynamic_image/resource/templates/create_table_migration.rb.tt
|
|
122
|
+
- lib/rails/generators/dynamic_image/upgrade/USAGE
|
|
123
|
+
- lib/rails/generators/dynamic_image/upgrade/templates/upgrade_migration.rb.tt
|
|
124
|
+
- lib/rails/generators/dynamic_image/upgrade/upgrade_generator.rb
|
|
125
|
+
- lib/tasks/dynamic_image.rake
|
|
119
126
|
homepage: https://github.com/elektronaut/dynamic_image
|
|
120
127
|
licenses:
|
|
121
128
|
- MIT
|
|
122
129
|
metadata:
|
|
130
|
+
bug_tracker_uri: https://github.com/elektronaut/dynamic_image/issues
|
|
131
|
+
changelog_uri: https://github.com/elektronaut/dynamic_image/blob/main/CHANGELOG.md
|
|
132
|
+
documentation_uri: https://www.rubydoc.info/gems/dynamic_image
|
|
123
133
|
rubygems_mfa_required: 'true'
|
|
134
|
+
source_code_uri: https://github.com/elektronaut/dynamic_image
|
|
124
135
|
rdoc_options: []
|
|
125
136
|
require_paths:
|
|
126
137
|
- lib
|
|
@@ -128,14 +139,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
128
139
|
requirements:
|
|
129
140
|
- - ">="
|
|
130
141
|
- !ruby/object:Gem::Version
|
|
131
|
-
version: 3.
|
|
142
|
+
version: 3.3.0
|
|
132
143
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
133
144
|
requirements:
|
|
134
145
|
- - ">="
|
|
135
146
|
- !ruby/object:Gem::Version
|
|
136
147
|
version: '0'
|
|
137
148
|
requirements: []
|
|
138
|
-
rubygems_version: 4.0.
|
|
149
|
+
rubygems_version: 4.0.16
|
|
139
150
|
specification_version: 4
|
|
140
151
|
summary: Rails plugin that simplifies image uploading and processing
|
|
141
152
|
test_files: []
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module DynamicImage
|
|
4
|
-
module Jobs
|
|
5
|
-
# = Create variant
|
|
6
|
-
#
|
|
7
|
-
# Creates an image variant.
|
|
8
|
-
class CreateVariant < ActiveJob::Base
|
|
9
|
-
queue_as :dis
|
|
10
|
-
|
|
11
|
-
discard_on Dis::Errors::NotFoundError
|
|
12
|
-
|
|
13
|
-
retry_on StandardError, attempts: 10, wait: :polynomially_longer
|
|
14
|
-
|
|
15
|
-
def perform(record, options, size)
|
|
16
|
-
size_v = Vector2d.parse(size)
|
|
17
|
-
DynamicImage::ProcessedImage.new(record, options)
|
|
18
|
-
.find_or_create_variant(size_v)
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
end
|
data/lib/dynamic_image/jobs.rb
DELETED