Ruby on rails 如何从多个字段中验证一个字段的存在

Ruby on rails 如何从多个字段中验证一个字段的存在,ruby-on-rails,validation,Ruby On Rails,Validation,我在回答我自己的问题——只是把这个贴在这里,以防它对其他人有所帮助。此代码允许您验证列表中是否存在一个字段。有关用法,请参见代码中的注释。只需将其粘贴到lib/custom\u validations.rb中,并将require“custom\u validations”添加到您的environment.rb中即可 #good post on how to do stuff like this http://www.marklunds.com/articles/one/312 module

我在回答我自己的问题——只是把这个贴在这里,以防它对其他人有所帮助。此代码允许您验证列表中是否存在一个字段。有关用法,请参见代码中的注释。只需将其粘贴到lib/custom\u validations.rb中,并将require“custom\u validations”添加到您的environment.rb中即可

#good post on how to do stuff like this  http://www.marklunds.com/articles/one/312

module ActiveRecord
  module Validations
    module ClassMethods

      # Use to check for this, that or those was entered... example:
      #  :validates_presence_of_at_least_one_field :last_name, :company_name  - would require either last_name or company_name to be filled in
      #  also works with arrays
      #  :validates_presence_of_at_least_one_field :email, [:name, :address, :city, :state] - would require email or a mailing type address
      def validates_presence_of_at_least_one_field(*attr_names)
        msg = attr_names.collect {|a| a.is_a?(Array) ? " ( #{a.join(", ")} ) " : a.to_s}.join(", ") +
                    "can't all be blank.  At least one field (set) must be filled in."
        configuration = {
          :on => :save,
          :message => msg }
        configuration.update(attr_names.extract_options!)

        send(validation_method(configuration[:on]), configuration) do |record|
          found = false
          attr_names.each do |a|
            a = [a] unless a.is_a?(Array)
            found = true
            a.each do |attr|
              value = record.respond_to?(attr.to_s) ? record.send(attr.to_s) : record[attr.to_s]
              found = !value.blank?
            end
            break if found
          end
          record.errors.add_to_base(configuration[:message]) unless found
        end
      end

    end
  end
end

这在Rails 3中适用,尽管我只是验证是否存在一个或另一个字段:

validates :last_name, :presence => {unless => Proc.new { |a| a.company_name.present? }, :message => "You must enter a last name, company name, or both"}

只有当公司名称为空时,才会验证姓氏的存在。您只需要一个,因为两者在错误条件下都是空的,所以在公司名称上也有一个验证器是多余的。唯一恼人的是,它在消息之前吐出了列名,我使用了关于人性化属性的问题的答案来回避它(只需将last_name人性化属性设置为“”

:除非=>'company_name'
只有当company_name为零时才为真,而不是空字符串。
除非=>Proc.new{| a | a.company_name.present?}
也将检查空字符串。