这是我在 Rails 5.2 中验证内容类型的解决方案,您可能知道它有一个陷阱,即附件一旦分配给模型就会被保存。它也可能适用于 Rails 6。我所做的是猴子补丁 ActiveStorage::Attachment 包含验证:
config/initializers/active_storage_attachment_validations.rb:
Rails.configuration.to_prepare do
ActiveStorage::Attachment.class_eval do
ALLOWED_CONTENT_TYPES = %w[image/png image/jpg image/jpeg].freeze
validates :content_type, content_type: { in: ALLOWED_CONTENT_TYPES, message: 'of attached files is not valid' }
end
end
app/validators/content_type_validator.rb:
class ContentTypeValidator < ActiveModel::EachValidator
def validate_each(record, attribute, _value)
return true if types.empty?
return true if content_type_valid?(record)
errors_options = { authorized_types: types.join(', ') }
errors_options[:message] = options[:message] if options[:message].present?
errors_options[:content_type] = record.blob&.content_type
record.errors.add(attribute, :content_type_invalid, errors_options)
end
private
def content_type_valid?(record)
record.blob&.content_type.in?(types)
end
def types
Array.wrap(options[:with]) + Array.wrap(options[:in])
end
end
由于在 Rails 5 中实现了attach 方法:
def attach(*attachables)
attachables.flatten.collect do |attachable|
if record.new_record?
attachments.build(record: record, blob: create_blob_from(attachable))
else
attachments.create!(record: record, blob: create_blob_from(attachable))
end
end
end
create! 方法会在验证失败时引发 ActiveRecord::RecordInvalid 异常,但它只需要被抢救,仅此而已。