ActiveStorage文件附件验证

时间:2018-01-08 22:09:16

标签: ruby-on-rails rails-activestorage ruby-on-rails-5.2

有没有办法用ActiveStorage验证附件?例如,如果我想验证内容类型或文件大小?

像Paperclip这样的方法会很棒!

  validates_attachment_content_type :logo, content_type: /\Aimage\/.*\Z/
  validates_attachment_size :logo, less_than: 1.megabytes

7 个答案:

答案 0 :(得分:14)

嗯,它很漂亮,但这可能是必要的,直到他们进行一些验证:

  validate :logo_validation

  def logo_validation
    if logo.attached?
      if logo.blob.byte_size > 1000000
        logo.purge
        errors[:base] << 'Too big'
      elsif !logo.blob.content_type.starts_with?('image/')
        logo.purge
        errors[:base] << 'Wrong format'
      end
    end
  end

答案 1 :(得分:8)

ActiveStorage目前不支持验证。根据{{​​3}}。

更新

Rails 6将支持ActiveStorage验证。

https://github.com/rails/rails/issues/31656

Uploaded files assigned to a record are persisted to storage when the record
is saved instead of immediately.
In Rails 5.2, the following causes an uploaded file in `params[:avatar]` to
be stored:
```ruby
@user.avatar = params[:avatar]
```
In Rails 6, the uploaded file is stored when `@user` is successfully saved.

答案 2 :(得分:6)

你可以使用真棒https://github.com/musaffa/file_validators宝石

null

我正在使用它与表单对象,所以我不是100%确定它是直接与AR一起工作但它应该...

答案 3 :(得分:2)

在以下宝石上出现:https://github.com/igorkasyanchuk/active_storage_validations

class User < ApplicationRecord
  has_one_attached :avatar
  has_many_attached :photos

  validates :name, presence: true

  validates :avatar, attached: true, content_type: 'image/png',
                                     dimension: { width: 200, height: 200 }
  validates :photos, attached: true, content_type: ['image/png', 'image/jpg', 'image/jpeg'],
                                     dimension: { width: { min: 800, max: 2400 },
                                                  height: { min: 600, max: 1800 }, message: 'is not given between dimension' }
end

答案 4 :(得分:1)

我找到了一种使用before_save回调验证和删除附件的方法。 这是一种有用的方法,因为如果您在事务处理期间验证文件(并且想要清除它),则在添加错误后它将回滚删除附件。

before_save :check_logo_file, on: %i[create update]

def check_favicon_content_type
    PartnerValidators::CustomPartnerFaviconValidator.new.validate(self)
end

module PartnerValidators
    class CustomPartnerFaviconValidator < ActiveModel::Validator
        ALLOWED_MIME_TYPES = %w(image/vnd.microsoft.icon image/x-icon image/png).freeze
        private_constant :ALLOWED_MIME_TYPES

        def validate(partner)
            if partner.favicon.attached? && invalid_content_type?(partner)
                partner.errors.add(:favicon, I18n.t("active_admin.errors.favicon"))
                partner.favicon.purge
            end
        end

        private

        def invalid_content_type?(partner)
            !partner.favicon.blob.content_type.in?(ALLOWED_MIME_TYPES)
        end
    end
end

答案 5 :(得分:0)

app/controllers/active_storage/direct_uploads_controller.rb文件中复制ActiveStorage的DirectUploadsController的内容并修改create方法。您可以向该控制器添加身份验证,在文件大小或mime类型上添加常规验证,因为此控制器的create方法将为要上传的文件创建url。因此,您可以通过控制此控制器的大小和mime类型来阻止任何文件上传。

一个简单的验证可以是:

# ...
def create
  raise SomeError if blob_args[:byte_size] > 10240 # 10 megabytes
  blob = ActiveStorage::Blob.create_before_direct_upload!(blob_args)
  render json: direct_upload_json(blob)
end
# ...

答案 6 :(得分:0)

这是我在Rails 5.2中验证内容类型的解决方案,您可能知道它有一个陷阱,那就是将附件分配给模型后立即对其进行保存。它可能也适用于Rails6。我所做的是猴子补丁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异常,但这仅需要挽救就可以了。