我有一个带有附件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
验证name
,short_description
和slug
的存在。
自实施以来,我有一个新的要求。我现在想允许用户与其他属性分开提交图像。
我不想更改基础模型。因此,我想引入一个单独的控制器和类来处理仅用于提交图像的表单。
我尝试了两种方法。
首先,我有一个简单的类来处理此问题:
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
模型以外的活动存储项目?
[仅使用一个模型就无法真正做到这一点。您需要使用活动存储验证来创建第二个“ 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
尝试一下
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
类。