ruby-on-rails Rails 6:如何在模型之外对ActiveStorage项目运行验证?

kgqe7b3p  于 2023-08-08  发布在  Ruby
关注(0)|答案(3)|浏览(119)

我有一个型号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是因为我想跳过对其他属性的验证--当字段未显示给用户时,为name列显示错误是没有意义的。)
我还尝试通过在模型之外运行验证来解决这个问题。但在这里,我很难理解如何将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型号以外的活动存储项目?

gajydyqb

gajydyqb1#

你不能用一个模型来做。您需要使用活动存储验证创建第二个“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

字符串

4uqofj5v

4uqofj5v2#

试试这个

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
  ...

字符串
如果User不强制Profile。然后,您可能希望将图像移动到User类。

eqoofvh9

eqoofvh93#

我也犯了同样的错误,我不得不建立一个通往模型的小桥梁。

class ApplicantForm
  include ActiveModel::Model
  include ActiveModel::Validations

  attr_accessor :applicant, :first_name, :last_name, :photo

  validates :first_name, :last_name, :photo, presence: true
  validate :format_and_size_of_photo

  def save
    if valid?
      applicant.update(first_name: first_name, last_name: last_name)
    end
  end

  def format_and_size_of_photo
    applicant.validate
    
    errors.add(:photo, applicant.errors[:photo]) if applicant.errors[:photo].present?
  end
end

字符串
在模型中,我有ActiveStorageValidations

相关问题