【发布时间】:2021-11-28 10:00:10
【问题描述】:
我目前正在开发一个使用 Rails 5.2.6 的项目。 (这是一个相当大的项目,我将无法更新rails版本)
我们使用 ActiveAdmin 来处理管理部分,我有一个模型,我在其中使用 ActiveStorage 保存徽标。
最近,我需要对该徽标属性进行验证。 (文件格式、大小和比例)。为此,我一直在搜索多种解决方案,包括 ActiveStorageValidations gem。
这个为我提供了一半的解决方案,因为验证器按预期工作,但即使验证器失败,徽标也会被存储并关联到模型。 (我被重定向到编辑表单,在徽标字段上显示不同的错误,但徽标仍会更新)。这显然是一个已知问题,来自据说在 Rails 6 中修复的 ActiveStorage,但我无法更新项目。 (根据我在 GitHub 上发现的问题,ActiveStorageValidations 也不想做任何事情)
最后,我设法“手动”制作了一个可行的解决方案,使用一些 before_actions 对图像进行必要的检查,并在某些检查失败时再次呈现编辑表单。
我还在此过程中向我的模型添加了一些错误,以便在呈现来自活动管理员的编辑视图时,错误会正确显示在表单和徽标字段的顶部。
这是后面的代码 (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
...
如果有人知道如何做到这一点,或者知道如何以更好的方式做事,任何线索都将不胜感激!
【问题讨论】:
-
嗨,我想我遇到了同样的问题。我修复了覆盖创建和更新方法以将错误放入
@my_model.errors。 github.com/activeadmin/inherited_resources/blob/… -
是的,或多或少的实现了。但是 chumakoff 对我们所做的事情给出了一个很好、更清晰的答案。
标签: ruby-on-rails ruby validation activeadmin