上面建议的用于覆盖作者的解决方案不工作.
第一个解决方案
基于ActiveStorage源代码at this line
您可以像这样覆盖has_many_attached 的作者:
class Model < ApplicationModel
has_many_attached :files
def files=(attachables)
attachables = Array(attachables).compact_blank
if attachables.any?
attachment_changes["files"] =
ActiveStorage::Attached::Changes::CreateMany.new("files", self, files.blobs + attachables)
end
end
end
重构/第二个解决方案
您可以创建一个模型关注点,该模型关注点将封装所有这些逻辑并使其更具动态性,方法是允许您指定您想要的 has_many_attached 字段老的行为,同时仍然为较新的 has_many_attached 字段保持新行为,如果您在启用新行为后添加任何行为。
在app/models/concerns/append_to_has_many_attached.rb
module AppendToHasManyAttached
def self.[](fields)
Module.new do
extend ActiveSupport::Concern
fields = Array(fields).compact_blank # will always return an array ( worst case is an empty array)
fields.each do |field|
field = field.to_s # We need the string version
define_method :"#{field}=" do |attachables|
attachables = Array(attachables).compact_blank
if attachables.any?
attachment_changes[field] =
ActiveStorage::Attached::Changes::CreateMany.new(field, self, public_send(field).public_send(:blobs) + attachables)
end
end
end
end
end
end
在你的模型中:
class Model < ApplicationModel
include AppendToHasManyAttached['files'] # you can include it before or after, order does not matter, explanation below
has_many_attached :files
end
注意:prepend 或 include 模块无关紧要,因为 ActiveStorage 生成的方法被添加到此 generated module 中,当您从 ActiveRecord::Base 继承时很早就调用 here
==> 所以你的作家将永远优先。
替代/最后解决方案:
如果您想要一些更加动态和健壮的东西,您仍然可以创建模型关注点,但是您可以像这样在模型的 attachment_reflections 中循环:
reflection_names = Model.reflect_on_all_attachments.filter { _1.macro == :has_many_attached }.map { _1.name.to_s } # we filter to exclude `has_one_attached` fields
# => returns ['files']
reflection_names.each do |name|
define_method :"#{name}=" do |attachables|
# ....
end
end
但是我相信要使其正常工作,您需要在对has_many_attached 的所有调用之后包含此模块,否则它将无法工作,因为反射数组不会被完全填充(对 has_many_attached 的每次调用都会附加到该数组)