Rails 6:如何在模型之外的ActiveStorage项目上运行验证?

问题描述 投票:0回答:2

我有一个带有附件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
  #...

除了图像验证(我正在使用active storage validation 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模型以外的活动存储项目?

ruby-on-rails rails-activestorage ruby-on-rails-6
2个回答
0
投票

[仅使用一个模型就无法真正做到这一点。您需要使用活动存储验证来创建第二个“ Image”或“ Attachment”类,然后才能首先创建该图像。

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

所以它看起来像这样:

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

0
投票

尝试一下

class ProfileImageFormSubmission

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

  def save
    record.assign_attributes(image: image_param)
    record.valid?

    if record.errors.exclude?(:image)
      record.save(validate: false)
    else
      record.errors.to_h.except(:image).each { |k,_| record.errors.delete(k) } # removing errors for other attributes
      false
    end
  end
  ...

如果Profile不是必须的User。然后,您可能需要将图像移到User类。

© www.soinside.com 2019 - 2024. All rights reserved.