Rails вложенные атрибуты: требуется не менее двух записей

Как я могу сделать так, чтобы для отправки продукта требуется как минимум две записи параметров?

class Product < ActiveRecord::Base
  belongs_to :user
  has_many :options, :dependent => :destroy
  accepts_nested_attributes_for :options, :allow_destroy => :true, :reject_if => proc { |attrs| attrs.all? { |k, v| v.blank? } }
  validates_presence_of :user_id, :created_at
  validates :description, :presence => true, :length => {:minimum => 0, :maximum => 500}
end

class Option < ActiveRecord::Base
  belongs_to :product
  validates :name, :length => {:minimum => 0, :maximum => 60}                  
end

Ответ 1

class Product < ActiveRecord::Base
  #... all your other stuff
  validate :require_two_options

  private
    def require_two_options
      errors.add(:base, "You must provide at least two options") if options.size < 2
    end
end

Ответ 2

Просто рассмотрение вопроса о кармаджунке: я бы использовал size вместо count, потому что если в некотором встроенном (и не сохраненном) вложенном объекте есть ошибки, он не будет считаться (его еще не в базе данных).

class Product < ActiveRecord::Base
  #... all your other stuff
  validate :require_two_options

  private
    def require_two_options
      errors.add(:base, "You must provide at least two options") if options.size < 2
    end
end

Ответ 3

Если ваша форма позволяет удалить записи, то .size не будет работать, так как включает записи, помеченные для уничтожения.

Мое решение было:

validate :require_two_options

private
 def require_two_options
    i = 0
    product_options.each do |option|
      i += 1 unless option.marked_for_destruction?
    end
    errors.add(:base, "You must provide at least two option") if i < 2
 end

Ответ 4

Код Tidier, протестированный с помощью Rails 5:

class Product < ActiveRecord::Base
  OPTIONS_SIZE_MIN = 2
  validate :require_two_options

  private

  def options_count_valid?
    options.reject(&:marked_for_destruction?).size >= OPTIONS_SIZE_MIN
  end

  def require_two_options
    errors.add(:base, 'You must provide at least two options') unless options_count_valid?
  end
end