You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

覆写rails_admin默认功能时回调执行顺序异常引发Mongoid错误

问题:RailsAdmin覆写逻辑导致Mongoid类型不匹配错误

我们通过config/initializers/rails_admin_index_override.rb和config/initializers/rails_admin_edit_override.rb文件覆写RailsAdmin的默认功能,但rails_admin_edit_override.rb中的自定义Edit动作逻辑会在数据格式化回调之前执行,触发如下Mongoid类型错误:

Mongoid::Errors::InvalidValue (
message:
  Value of type String cannot be written to a field of type Array
summary:
  Tried to set a value of type String to a field of type Array
resolution:
  Verify if the value to be set correspond to field definition):
  
config/initializers/rails_admin_edit_override.rb:22:in `block (2 levels) in <class:Edit>'

当前使用的覆写代码:

module RailsAdmin
  module Config
    module Actions
      class Edit < RailsAdmin::Config::Actions::Base
        register_instance_option :member do
          true
        end

        register_instance_option :http_methods do
          [:get, :put]
        end

        register_instance_option :controller do
          proc do
            if request.get? # EDIT
              respond_to do |format|
                format.html { render @action.template_name }
                format.js { render @action.template_name, layout: false }
              end
            elsif request.put? # UPDATE
              exclude_models = ['product', 'manufacturer', 'language_code', 'vip_influencer_video_note', 'video', 'celebrity', 'vertical']

              sanitize_params_for!( request.xhr? ? :modal : :update ) unless exclude_models.include?(params[:model_name])
              @object.assign_attributes(params[@abstract_model.param_key])
              @authorization_adapter && @authorization_adapter.attributes_for(:update, @abstract_model).each do |name, value|
                @object.send("#{name}=", value)
              end
            end
          end
        end
      end
    end
  end
end

解决方案

错误核心原因是:被排除的模型未经过RailsAdmin的参数格式化处理,原始字符串参数直接赋值给Mongoid数组字段导致类型不匹配。要让数据格式化回调优先执行,可通过以下两种方式修复:

方式一:对排除模型手动执行参数格式化

在调用assign_attributes之前,先用RailsAdmin内置参数过滤器处理参数,确保字段类型转换完成:

修改覆写代码中的UPDATE分支:

elsif request.put? # UPDATE
  exclude_models = ['product', 'manufacturer', 'language_code', 'vip_influencer_video_note', 'video', 'celebrity', 'vertical']
  model_name = params[:model_name]

  # 统一处理参数格式化:原生sanitize或手动过滤
  if exclude_models.include?(model_name)
    # 对排除模型,手动触发RailsAdmin的参数过滤逻辑
    params[@abstract_model.param_key] = @abstract_model.model.param_filter.filter(
      params[@abstract_model.param_key], 
      @abstract_model, 
      request.xhr? ? :modal : :update
    )
  else
    sanitize_params_for!( request.xhr? ? :modal : :update )
  end

  # 参数已完成格式化,再执行赋值逻辑
  @object.assign_attributes(params[@abstract_model.param_key])
  @authorization_adapter && @authorization_adapter.attributes_for(:update, @abstract_model).each do |name, value|
    @object.send("#{name}=", value)
  end

  # 补充原生保存与响应逻辑(原代码缺失,会导致只赋值不保存)
  if @object.save
    flash[:success] = t('admin.flash.successful', name: @model_config.label, action: t('admin.actions.edit.done'))
    redirect_to_on_success
  else
    flash[:error] = t('admin.flash.error', name: @model_config.label, action: t('admin.actions.edit.done'))
    render :edit
  end
end

方式二:继承原生Edit动作而非Base

避免完全重写controller逻辑,继承RailsAdmin原生Edit动作,仅修改需自定义的部分,原生参数格式化流程会自动优先执行:

module RailsAdmin
  module Config
    module Actions
      # 继承原生Edit动作,而非Base
      class Edit < RailsAdmin::Config::Actions::Edit
        register_instance_option :controller do
          proc do
            if request.get? # EDIT
              # 保留原生GET逻辑,或自定义
              super()
            elsif request.put? # UPDATE
              exclude_models = ['product', 'manufacturer', 'language_code', 'vip_influencer_video_note', 'video', 'celebrity', 'vertical']
              
              # 先执行原生参数处理与赋值逻辑
              super()
              
              # 在这里添加自定义逻辑(如额外属性赋值、权限处理等)
            end
          end
        end
      end
    end
  end
end

内容的提问来源于stack exchange,提问作者Suhas Shinde

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 17:53:19