如何手动触发Rails ActiveRecord验证?(ActiveAdmin)



我目前正在做一个使用Rails 5.2.6的项目。(这是一个相当大的项目,我不能更新rails版本)

我们使用ActiveAdmin来处理管理部分,我有一个模型,我用ActiveStorage保存一个标志。

最近,我需要对徽标属性执行验证。(档案格式、大小及比例)。为此,我一直在寻找多种解决方案,包括ActiveStorageValidations gem。

这个为我提供了一半的解决方案,因为验证器按预期工作,但是即使验证器失败,徽标也会被存储并关联到模型。(我被重定向到编辑表单与不同的错误显示在徽标字段,但仍然会更新徽标)。这显然是一个已知的问题,从ActiveStorage据称在Rails 6中修复,但我无法更新项目。(和ActiveStorageValidations不想做任何关于它以及根据我在GitHub上发现的问题)

最后,我设法"手工"制作了一个可行的解决方案,使用一些before_actions对图像进行必要的检查,并在某些检查失败之前再次呈现编辑表单。

我还在这个过程中向我的模型添加了一些错误,以便在呈现active admin的编辑视图时,错误正确地显示在表单和徽标字段的顶部。

下面是(admin/mymodel.rb) 后面的代码
controller do
before_action :prevent_save_if_invalid_logo, only: [:create, :update]
private
# Active Storage Validations display error messages but still attaches the file and persist the model
# That's a known issue, which is solved in Rails 6
# This is a workaround to make it work for our use case
def prevent_save_if_invalid_logo
return unless params[:my_model][:logo]
file = params[:my_model][:logo]
return if valid_logo_file_format(file) && valid_logo_aspect_ratio(file) && valid_logo_file_size(file)
if @my_model.errors.any?
render 'edit' 
end
end
def valid_logo_aspect_ratio(file)
width, height = IO.read(file.tempfile.path)[0x10..0x18].unpack('NN')

valid = (2.to_f / 1).round(3) == (width.to_f / height).round(3) ? true : false
@my_model.errors[:logo] << "Aspect ratio must be 2 x 1" unless valid
valid
end
def valid_logo_file_size(file)
valid = File.size(file.tempfile) < 200.kilobytes ? true : false
@my_model.errors[:logo] << "File size must be < 200 kb" unless valid
valid
end
def valid_logo_file_format(file)
content_type = file.present? && file.content_type
@my_model.errors[:logo] << "File must be a PNG" unless content_type
content_type == "image/png" ? true : content_type
end
end

这种方法可以很好地工作,但现在我的问题是,如果其他表单上的错误发生在同一时间比标志错误(必填字段或其他东西),那么就没有得到验证,错误并不像这个呈现编辑视图的显示会发生其他验证。

我的问题是,我是否有任何方法在这个级别手动触发我的模型上的验证,以便每个其他字段都得到验证和@my_model。Errors填充正确的错误,从而使表单能够显示所有表单错误,无论是否涉及徽标。

像这样:

...
def prevent_save_if_invalid_logo
return unless params[:my_model][:logo]

file = params[:my_model][:logo]
return if valid_logo_file_format(file) && valid_logo_aspect_ratio(file) && valid_logo_file_size(file)

if @my_model.errors.any?
# VALIDATE WHOLE FORM SO OTHER ERRORS ARE CHECKED
render 'edit' 
end
end
...

如果有人有关于如何做到这一点的想法,或关于如何以更好的方式做事的线索,任何线索将不胜感激!

方法一:

与其显式地呈现'edit',它会停止默认的ActiveAdmin流程,你可以简单地删除文件表单参数,让事情按照标准的方式进行:

before_action :prevent_logo_assignment_if_invalid, only: [:create, :update]
def prevent_logo_assignment_if_invalid
return unless params[:my_model][:logo]
file = params[:my_model][:logo]
return if valid_logo_file_format?(file) && valid_logo_aspect_ratio?(file) && valid_logo_file_size?(file)
params[:my_model][:logo] = nil
# or params[:my_model].delete(:logo)
end

方法2:

思路是相同的,但您也可以在模型级别上这样做。您可以通过覆盖ActiveStorage的setter方法来阻止文件分配:

class MyModel < ApplicationModel
def logo=(file)
return unless valid_logo?(file) 
super
end

顺便说一下,您的valid_logo_file_format方法将始终返回true

相关内容

  • 没有找到相关文章

最新更新