如何创建Question时保留自身验证并跳过Mappable模块的验证?
问题:创建Question实例时跳过Mappable模块验证,保留自身验证规则
我现有如下Question类:
class Question < ApplicationRecord include Mappable # 其他代码... end
需求是创建Question实例时,保留Question自身的所有验证规则,但跳过来自Mappable模块的验证规则。目前我用question.save(validate: false)可以跳过所有验证,但希望改成类似question.save(mappable_validate: false)的方式,只跳过Mappable模块的验证。
补充:Mappable模块代码
module Mappable extend ActiveSupport::Concern included do attr_accessor :skip_map has_one :map_location, dependent: :destroy accepts_nested_attributes_for :map_location, allow_destroy: true, reject_if: :all_blank validate :map_must_be_valid, on: :create, if: :feature_maps? def map_must_be_valid return true if skip_map? unless map_location.try(:available?) skip_map_error = "Map error" errors.add(:skip_map, skip_map_error) end end def feature_maps? Setting["feature.map"].present? end def skip_map? skip_map == "1" end end end
解决方案
方法1:利用现有skip_map属性快速实现
Mappable模块已经内置了skip_map属性和skip_map?方法,直接设置该属性就能跳过验证:
question = Question.new(...) question.skip_map = "1" # 触发skip_map?返回true,跳过map_must_be_valid验证 question.save
这种方式不需要修改模块代码,直接用现有逻辑就能满足需求,同时保留Question自身的所有验证。
方法2:扩展save方法支持mappable_validate参数
如果想要更贴合你期望的save(mappable_validate: false)写法,可以修改Mappable模块,添加对自定义参数的支持:
module Mappable extend ActiveSupport::Concern included do attr_accessor :skip_map attr_accessor :skip_mappable_validation # 新增属性标记是否跳过验证 has_one :map_location, dependent: :destroy accepts_nested_attributes_for :map_location, allow_destroy: true, reject_if: :all_blank # 修改验证触发条件,新增对skip_mappable_validation的判断 validate :map_must_be_valid, on: :create, if: -> { feature_maps? && !skip_mappable_validation } def map_must_be_valid return true if skip_map? unless map_location.try(:available?) skip_map_error = "Map error" errors.add(:skip_map, skip_map_error) end end def feature_maps? Setting["feature.map"].present? end def skip_map? skip_map == "1" end # 重写save方法,处理自定义参数 def save(options = {}) if options[:mappable_validate] == false self.skip_mappable_validation = true # 移除自定义参数后调用父类save方法 result = super(options.except(:mappable_validate)) self.skip_mappable_validation = nil # 重置标记 result else super(options) end end end end
修改后就可以直接用你想要的方式调用:
question.save(mappable_validate: false)
这种方式更直观,也不会影响原有skip_map的功能。
内容的提问来源于stack exchange,提问作者CUB5
相关产品推荐
相关产品推荐

