Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails nested attributes: require at least two records

How can I make it so that at least two option records are required to submit a product?

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
like image 341
morcutt Avatar asked Nov 30 '10 00:11

morcutt


4 Answers

If your form allows records to be deleted then .size will not work as it includes the records marked for destruction.

My solution was:

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
like image 62
TrevTheDev Avatar answered Nov 07 '22 18:11

TrevTheDev


Tidier code, tested with 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
like image 21
Sebastian Avatar answered Nov 03 '22 06:11

Sebastian


Just a consideration about karmajunkie answer: I would use size instead of count because if some built (and not saved) nested object has errors, it would not be considered (its not on database yet).

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
like image 12
Leandro Gerhardinger Avatar answered Nov 07 '22 17:11

Leandro Gerhardinger


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
like image 17
Keith Gaddis Avatar answered Nov 07 '22 19:11

Keith Gaddis