diff --git a/activestorage/CHANGELOG.md b/activestorage/CHANGELOG.md index ff0c20f263..c5fafc80ec 100644 --- a/activestorage/CHANGELOG.md +++ b/activestorage/CHANGELOG.md @@ -2,17 +2,17 @@ ```ruby class User < ActiveRecord::Base - has_one_attached :avatar, variants: { - thumb: { resize: "100x100" }, - medium: { resize: "300x300", monochrome: true } - } + has_one_attached :avatar do |attachable| + attachable.variant :thumb, resize: "100x100" + attachable.variant :medium, resize: "300x300", monochrome: true + end end class Gallery < ActiveRecord::Base - has_many_attached :photos, variants: { - thumb: { resize: "100x100" }, - medium: { resize: "300x300", monochrome: true } - } + has_many_attached :photos do |attachable| + attachable.variant :thumb, resize: "100x100" + attachable.variant :medium, resize: "300x300", monochrome: true + end end <%= image_tag user.avatar.variant(:thumb) %> diff --git a/activestorage/app/models/active_storage/attachment.rb b/activestorage/app/models/active_storage/attachment.rb index 6910848285..01c4d1bd26 100644 --- a/activestorage/app/models/active_storage/attachment.rb +++ b/activestorage/app/models/active_storage/attachment.rb @@ -66,7 +66,7 @@ class ActiveStorage::Attachment < ActiveRecord::Base end def variants - record.attachment_reflections[name]&.options[:variants] + record.attachment_reflections[name]&.variants end end diff --git a/activestorage/lib/active_storage/attached/model.rb b/activestorage/lib/active_storage/attached/model.rb index 939dec37a6..9e809af5ba 100644 --- a/activestorage/lib/active_storage/attached/model.rb +++ b/activestorage/lib/active_storage/attached/model.rb @@ -40,7 +40,7 @@ module ActiveStorage # has_one_attached :avatar, service: :s3 # end # - def has_one_attached(name, dependent: :purge_later, service: nil, variants: {}) + def has_one_attached(name, dependent: :purge_later, service: nil) validate_service_configuration(name, service) generated_association_methods.class_eval <<-CODE, __FILE__, __LINE__ + 1 @@ -72,9 +72,10 @@ module ActiveStorage :has_one_attached, name, nil, - { dependent: dependent, service_name: service, variants: variants }, + { dependent: dependent, service_name: service }, self ) + yield reflection if block_given? ActiveRecord::Reflection.add_attachment_reflection(self, name, reflection) end @@ -110,7 +111,7 @@ module ActiveStorage # has_many_attached :photos, service: :s3 # end # - def has_many_attached(name, dependent: :purge_later, service: nil, variants: {}) + def has_many_attached(name, dependent: :purge_later, service: nil) validate_service_configuration(name, service) generated_association_methods.class_eval <<-CODE, __FILE__, __LINE__ + 1 @@ -159,9 +160,10 @@ module ActiveStorage :has_many_attached, name, nil, - { dependent: dependent, service_name: service, variants: variants }, + { dependent: dependent, service_name: service }, self ) + yield reflection if block_given? ActiveRecord::Reflection.add_attachment_reflection(self, name, reflection) end diff --git a/activestorage/lib/active_storage/reflection.rb b/activestorage/lib/active_storage/reflection.rb index ce248c88b5..5bec40d2d3 100644 --- a/activestorage/lib/active_storage/reflection.rb +++ b/activestorage/lib/active_storage/reflection.rb @@ -2,9 +2,19 @@ module ActiveStorage module Reflection + class HasAttachedReflection < ActiveRecord::Reflection::MacroReflection #:nodoc: + def variant(name, transformations) + variants[name] = transformations + end + + def variants + @variants ||= {} + end + end + # Holds all the metadata about a has_one_attached attachment as it was # specified in the Active Record class. - class HasOneAttachedReflection < ActiveRecord::Reflection::MacroReflection #:nodoc: + class HasOneAttachedReflection < HasAttachedReflection #:nodoc: def macro :has_one_attached end @@ -12,7 +22,7 @@ module ActiveStorage # Holds all the metadata about a has_many_attached attachment as it was # specified in the Active Record class. - class HasManyAttachedReflection < ActiveRecord::Reflection::MacroReflection #:nodoc: + class HasManyAttachedReflection < HasAttachedReflection #:nodoc: def macro :has_many_attached end diff --git a/activestorage/test/models/reflection_test.rb b/activestorage/test/models/reflection_test.rb index d8cd2a0ec9..4e258eb8e9 100644 --- a/activestorage/test/models/reflection_test.rb +++ b/activestorage/test/models/reflection_test.rb @@ -14,7 +14,7 @@ class ActiveStorage::ReflectionTest < ActiveSupport::TestCase assert_equal :local, reflection.options[:service_name] reflection = User.reflect_on_attachment(:avatar_with_variants) - assert_instance_of Hash, reflection.options[:variants] + assert_instance_of Hash, reflection.variants end test "reflection on a singular attachment with the same name as an attachment on another model" do @@ -33,7 +33,7 @@ class ActiveStorage::ReflectionTest < ActiveSupport::TestCase assert_equal :local, reflection.options[:service_name] reflection = User.reflect_on_attachment(:highlights_with_variants) - assert_instance_of Hash, reflection.options[:variants] + assert_instance_of Hash, reflection.variants end test "reflecting on all attachments" do diff --git a/activestorage/test/test_helper.rb b/activestorage/test/test_helper.rb index 5a866c3f95..47d468324c 100644 --- a/activestorage/test/test_helper.rb +++ b/activestorage/test/test_helper.rb @@ -119,11 +119,15 @@ class User < ActiveRecord::Base has_one_attached :avatar has_one_attached :cover_photo, dependent: false, service: :local - has_one_attached :avatar_with_variants, variants: { thumb: { resize: "100x100" } } + has_one_attached :avatar_with_variants do |attachable| + attachable.variant :thumb, resize: "100x100" + end has_many_attached :highlights has_many_attached :vlogs, dependent: false, service: :local - has_many_attached :highlights_with_variants, variants: { thumb: { resize: "100x100" } } + has_many_attached :highlights_with_variants do |attachable| + attachable.variant :thumb, resize: "100x100" + end end class Group < ActiveRecord::Base diff --git a/guides/source/active_storage_overview.md b/guides/source/active_storage_overview.md index 8b0104cd9e..6491adced8 100644 --- a/guides/source/active_storage_overview.md +++ b/guides/source/active_storage_overview.md @@ -332,11 +332,13 @@ class User < ApplicationRecord end ``` -You can configure specific variants per attachment using the `variants` option: +You can configure specific variants per attachment by calling the `variant` method on yielded attachable object: ```ruby class User < ApplicationRecord - has_one_attached :avatar, variants: { thumb: { resize: "100x100" } } + has_one_attached :avatar do |attachable| + attachable.variant :thumb, resize: "100x100" + end end ``` @@ -396,11 +398,13 @@ class Message < ApplicationRecord end ``` -Configuring specific variants is done the same way as `has_one_attached`, by using the `variants` option: +Configuring specific variants is done the same way as `has_one_attached`, by calling the `variant` method on the yielded attachable object: ```ruby class Message < ApplicationRecord - has_many_attached :images, variants: { thumb: { resize: "100x100" } } + has_many_attached :images do |attachable| + attachable.variant :thumb, resize: "100x100" + end end ```