DRY方式使用相同的验证来纠正字段

时间:2015-10-26 19:46:46

标签: ruby-on-rails

我在Rails中有几个表,其字符串字段必须与表CvTerm(controlled_vocabulary的缩写)指定的一组术语匹配。 CvTerm用作表格和字段的特定白名单;例如,表Foo可能有一个字段Bar,其中唯一允许的条目为BazBaxQuux,其中有CvTerms为每个允许的条目创建。

我编写了一个自定义验证器,以确保用户分配给这些字段的值与为表设置的值匹配;此验证器可以在所有模型中用作单行,validates :field, is_controlled: true

class IsControlledValidator < ActiveModel::EachValidator
    def validate_each(record, attribute, value)
        if options[:has_context]
            allowed_terms = CvTerm.where({
                :related_table => record.class.to_s,
                :related_field => attribute.to_s,
                :context_table => record.related_type
            }).map(&:term)
        else
            allowed_terms = CvTerm.where(:related_table => record.class.to_s, :related_field => attribute.to_s).map(&:term)
        end
        unless allowed_terms.include?(value)
            record.errors[attribute] << "must be included in the allowed terms:\n#{allowed_terms.join("\n")}"
        end
    end
end

这很方便在我的模型中实现并且几乎按预期工作,但它区分大小写:强制用户手动确保大小写与最初输入的允许术语完全相同会非常烦人。

除了在验证器中进行这样的案例修正,我理解这是不赞成的,有没有办法做到这一点,不需要我个别地纠正每个受控场?

1 个答案:

答案 0 :(得分:0)

我会做几件事。

  1. 使用pluck而不是映射,它在sql上更快,你不必循环来获得该术语。

  2. 而不是直接在哪里做类似或ilike(mysql vs postgres)来消除区分大小写

  3. (可能)将您的搜索移动到查询对象中。