lib/active_storage/attached/model.rb in activestorage-6.0.6.1 vs lib/active_storage/attached/model.rb in activestorage-6.1.0.rc1

- old
+ new

@@ -1,16 +1,18 @@ # frozen_string_literal: true +require "active_support/core_ext/object/try" + module ActiveStorage # Provides the class-level DSL for declaring an Active Record model's attachments. module Attached::Model extend ActiveSupport::Concern class_methods do # Specifies the relation between a single attachment and the model. # - # class User < ActiveRecord::Base + # class User < ApplicationRecord # has_one_attached :avatar # end # # There is no column defined on the model side, Active Storage takes # care of the mapping between your records and the attachment. @@ -28,12 +30,23 @@ # The system has been designed to having you go through the ActiveStorage::Attached::One # proxy that provides the dynamic proxy to the associations and factory methods, like +attach+. # # If the +:dependent+ option isn't set, the attachment will be purged # (i.e. destroyed) whenever the record is destroyed. - def has_one_attached(name, dependent: :purge_later) + # + # If you need the attachment to use a service which differs from the globally configured one, + # pass the +:service+ option. For instance: + # + # class User < ActiveRecord::Base + # has_one_attached :avatar, service: :s3 + # end + # + def has_one_attached(name, dependent: :purge_later, service: nil) + validate_service_configuration(name, service) + generated_association_methods.class_eval <<-CODE, __FILE__, __LINE__ + 1 + # frozen_string_literal: true def #{name} @active_storage_attached ||= {} @active_storage_attached[:#{name}] ||= ActiveStorage::Attached::One.new("#{name}", self) end @@ -54,20 +67,23 @@ after_save { attachment_changes[name.to_s]&.save } after_commit(on: %i[ create update ]) { attachment_changes.delete(name.to_s).try(:upload) } - ActiveRecord::Reflection.add_attachment_reflection( - self, + reflection = ActiveRecord::Reflection.create( + :has_one_attached, name, - ActiveRecord::Reflection.create(:has_one_attached, name, nil, { dependent: dependent }, self) + nil, + { dependent: dependent, service_name: service }, + self ) + ActiveRecord::Reflection.add_attachment_reflection(self, name, reflection) end # Specifies the relation between multiple attachments and the model. # - # class Gallery < ActiveRecord::Base + # class Gallery < ApplicationRecord # has_many_attached :photos # end # # There are no columns defined on the model side, Active Storage takes # care of the mapping between your records and the attachments. @@ -85,12 +101,23 @@ # The system has been designed to having you go through the ActiveStorage::Attached::Many # proxy that provides the dynamic proxy to the associations and factory methods, like +#attach+. # # If the +:dependent+ option isn't set, all the attachments will be purged # (i.e. destroyed) whenever the record is destroyed. - def has_many_attached(name, dependent: :purge_later) + # + # If you need the attachment to use a service which differs from the globally configured one, + # pass the +:service+ option. For instance: + # + # class Gallery < ActiveRecord::Base + # has_many_attached :photos, service: :s3 + # end + # + def has_many_attached(name, dependent: :purge_later, service: nil) + validate_service_configuration(name, service) + generated_association_methods.class_eval <<-CODE, __FILE__, __LINE__ + 1 + # frozen_string_literal: true def #{name} @active_storage_attached ||= {} @active_storage_attached[:#{name}] ||= ActiveStorage::Attached::Many.new("#{name}", self) end @@ -128,15 +155,27 @@ after_save { attachment_changes[name.to_s]&.save } after_commit(on: %i[ create update ]) { attachment_changes.delete(name.to_s).try(:upload) } - ActiveRecord::Reflection.add_attachment_reflection( - self, + reflection = ActiveRecord::Reflection.create( + :has_many_attached, name, - ActiveRecord::Reflection.create(:has_many_attached, name, nil, { dependent: dependent }, self) + nil, + { dependent: dependent, service_name: service }, + self ) + ActiveRecord::Reflection.add_attachment_reflection(self, name, reflection) end + + private + def validate_service_configuration(association_name, service) + if service.present? + ActiveStorage::Blob.services.fetch(service) do + raise ArgumentError, "Cannot configure service :#{service} for #{name}##{association_name}" + end + end + end end def attachment_changes #:nodoc: @attachment_changes ||= {} end