Подтвердить что ты не робот

Rails: как требовать, чтобы хотя бы одно поле не было пустым

Я знаю, что может потребоваться поле, добавив validates_presence_of :field к модели. Однако, как мне нужно, чтобы хотя бы одно поле было обязательным, не требуя какого-либо конкретного поля?

заблаговременно

- Deb

4b9b3361

Ответ 1

Вы можете использовать:

validate :any_present?

def any_present?
  if %w(field1 field2 field3).all?{|attr| self[attr].blank?}
    errors.add :base, "Error message"
  end
end

EDIT: обновлено от исходного ответа для Rails 3+ в соответствии с комментарием.

Но вы должны указать имена полей вручную. Вы можете получить все столбцы содержимого модели с помощью Model.content_columns.map(&:name), но она будет включать столбцы created_at и updated_at, и это, вероятно, не то, что вы хотите.

Ответ 2

Добавьте к вашей модели метод validate:

def validate
  if field1.blank? and field2.blank? and field3.blank? # ...
    errors.add_to_base("You must fill in at least one field")
  end
end

Ответ 3

Здесь используется многоразовая версия:

class AnyPresenceValidator < ActiveModel::Validator
  def validate(record)
    unless options[:fields].any?{|attr| record[attr].present?}
      record.errors.add(:base, :blank)
    end
  end
end

Вы можете использовать его в своей модели с помощью:

validates_with AnyPresenceValidator, fields: %w(field1 field2 field3)

Ответ 4

Я считаю, что что-то вроде следующего может работать

class MyModel < ActiveRecord::Base
   validate do |my_model|
      my_model.my_validation
   end

   def my_validation      
      errors.add_to_base("Your error message") if self.blank? 
      #or self.attributes.blank? - not sure
   end
end

Ответ 5

Идем дальше с правильным ответом @Votya, вот способ получить все столбцы, кроме created_at и updated_at (и, возможно, любые другие, которые вы хотите выкинуть):

# Get all column names as an array and reject the ones we don't want
Model.content_columns.map(&:name).reject {|i| i =~ /(created|updated)_at/}

Например:

 1.9.3p327 :012 > Client.content_columns.map(&:name).reject {|i| i =~ /(created|updated)_at/}
 => ["primary_email", "name"]