繁体   English   中英

Rails 6:如何对模型外的 ActiveStorage 项运行验证?

[英]Rails 6: How can I run validations on an ActiveStorage item outside of the model?

我有一个模型Profile ,其中包含一个附件image

class Profile < ApplicationRecord
  belongs_to :user, dependent: :destroy

  has_one_attached :image
  validates :image,
            content_type: [:gif, :png, :jpg, :jpeg],
            size: { less_than: 2.megabytes , message: 'must be less than 2MB in size' }
  after_initialize :set_default_image

  has_many :gallery_items, dependent: :destroy
  accepts_nested_attributes_for :gallery_items, allow_destroy: true

  validates :name, :short_description, :slug, presence: true
  #...

除了图像验证(我正在使用活动存储验证 gem ), Profile验证nameshort_descriptionslug的存在。

自从实现了这个,我在视图中有一个新的需求。 我现在希望允许用户单独提交图像与其他属性。

我不想改变底层模型。 因此,我想引入一个单独的控制器和类来处理单独提交图像的表单。

我试过两种方法。

首先,我有一个简单的类来处理这个:

class ProfileImageFormSubmission
  def initialize(record, params)
    @params = params
    @record = record
  end

  def save
    record.update_attribute(:image, image_param)
  end

  private

  attr_accessor :params, :record

  def image_param
    params.fetch(record_param).require(:image)
  end

  def record_param
    record.class.name.underscore.to_sym
  end
end

它会在我的控制器中被调用,如下所示:

class ProfileImagesController < ApplicationController
  before_action :require_login

  def update
    @profile = Profile.find_by(user_id: current_user.id)

    if ProfileImageFormSubmission.new(@profile, params).save
      #...

问题是,图像未经验证,因此无论如何都附加到配置文件中。 (我使用#update_attribute是因为我想跳过对其他属性的验证——当字段未呈现给用户时,为名称列显示错误是没有意义的。)

我还尝试通过在模型之外运行验证来解决这个问题。 但是在这里,我很难理解如何将ActiveStorage与一个普通的旧 Ruby 对象集成。

class ProfileImageFormSubmission
  include ActiveModel::Model
  include ActiveStorage
  include ActiveStorageValidations

  attr_accessor :record, :params
  has_one_attached :image

  validates :image,
          content_type: [:gif, :png, :jpg, :jpeg],
          size: { less_than: 2.megabytes , message: 'must be less than 2MB in size' }

  def initialize(record, params)
    @params = params
    @record = record
  end

  def save
    binding.pry
    record.update_attribute(:image, image_param)

    if record.invalid?
      record.restore_attributes
      return false
    end
  end

  # This model is not backed by a table
  def persisted?
    false
  end

  private

  def image_param
    params.fetch(record_name).require(:image)
  end

  def object_name
    record.class.name.underscore.to_sym
  end
end

我什至无法实例化上面的类,因为它失败并出现以下错误:

NoMethodError (undefined method `has_one_attached' for ProfileImageFormSubmission:Class):

单独验证活动存储项目的最佳方法是什么?

是否可以在单列上运行验证而不触发其他验证错误?

是否可以在ApplicationRecord模型之外使用活动存储项?

你真的不能只用一个模型来做到这一点。 您需要使用活动存储验证创建第二个“图像”或“附件”类,然后您将能够首先创建图像。

即使可能将所有内容都保留在一个模型中,跳过验证也会导致数据不一致。 将其分开将确保您的数据库中的每条记录都是有效的,并且您不会遇到意外状态(例如没有名称的配置文件,即使您正在“验证”其存在)。

所以它看起来像这样:

class Image < ApplicationRecord
  (...)

  has_one_attached :file
  validates :file,
            content_type: [:gif, :png, :jpg, :jpeg],
            size: { less_than: 2.megabytes , message: 'must be less than 2MB in size' }

  (...)
end

class Profile < ApplicationRecord
  (...)

  has_one :image # or belongs to

  (...)
end

尝试这个

class ProfileImageFormSubmission

  def initialize(record, params)
    @params = params
    @record = record
  end

  def save
    record.assign_attributes(image: image_param)
    record.valid?
    record.errors.to_hash.except(:image).each { |k,_| record.errors.delete(k) } # removing errors for other attributes

    return false if record.errors.any?

    record.save(validate: false)
  end
  ...

如果Profile对于User不是必需的。 然后您可能希望将图像移动到User类。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM