如何在ActiveAdmin中手动触发Rails ActiveRecord模型校验?
实现方案
你可以在logo校验失败后,先手动给模型赋值表单提交的参数,再调用valid?触发全量校验,所有字段的错误会自动合并到@my_model.errors中,再渲染编辑页即可同时展示全部错误。
ActiveAdmin的参数赋值默认在before_action之后执行,所以你需要手动调用参数赋值逻辑,修改后的代码如下:
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] logo_valid = valid_logo_file_format(file) && valid_logo_aspect_ratio(file) && valid_logo_file_size(file) return if logo_valid # 手动赋值表单参数,触发全量校验 @my_model.assign_attributes(permitted_params[:my_model]) @my_model.valid? render 'edit' 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) @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 @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 valid = content_type == "image/png" @my_model.errors[:logo] << "File must be a PNG" unless valid valid end end
注意事项
- 这里直接使用
permitted_params[:my_model]获取ActiveAdmin配置好的白名单参数,不需要重复写参数过滤逻辑 - 原代码中
valid_logo_file_format方法返回值存在逻辑问题,非PNG格式时返回的是content_type字符串而非布尔值,会导致校验判断异常,已修正为统一返回布尔值 - 手动调用
assign_attributes和valid?不会触发ActiveStorage的附件持久化,不会出现校验失败但附件被保存的问题
内容的提问来源于stack exchange,提问作者Slth
相关产品推荐
相关产品推荐

