我目前正在使用 Rails 5.2.6 進行專案。(這是一個相當大的專案,我將無法更新 rails 版本)
我們使用 ActiveAdmin 來處理管理部分,我有一個模型,我在其中使用 ActiveStorage 保存徽標。
最近,我需要對該徽標屬性執行驗證。(檔案格式、大小和比例)。就此而言,我一直在尋找多種解決方案,包括 ActiveStorageValidations gem。
這個為我提供了一半的解決方案,因為驗證器按預期作業,但即使驗證器失敗,徽標也會被存盤并關聯到模型。(我被重定向到編輯表單,在徽標欄位上顯示了不同的錯誤,但徽標仍然會更新)。這顯然是一個已知問題,來自 ActiveStorage,據稱已在 Rails 6 中修復,但我無法更新該專案。(根據我在 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
...
如果有人有關于如何做到這一點的想法,或者關于如何以更好的方式做事的線索,任何線索將不勝感激!
uj5u.com熱心網友回復:
方法一:
您可以簡單地洗掉檔案表單引數并讓事情按照標準方式進行,而不是顯式呈現停止默認 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
方法二:
這個想法是一樣的,但你也可以在模型級別上做到這一點。您可以通過覆寫 ActiveStorage 的 setter 方法來阻止檔案分配:
class MyModel < ApplicationModel
def logo=(file)
return unless valid_logo?(file)
super
end
順便說一句,您的valid_logo_file_format方法將始終回傳true。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/312712.html
