Rails accepts_nested_attributes count validation
Asked Answered
S

2

7

I've got three models. Sales, items, and images. I'd like to validate that when a sale is created there are at least three photos per sale and one or more items. What would be the best way to achieve this?

Sales Model:

class Sale < ActiveRecord::Base
   has_many :items, :dependent => :destroy
   has_many :images, :through => :items

   accepts_nested_attributes_for :items, :reject_if => lambda { |a| a[:title].blank? }, :allow_destroy => true
end

Items Model:

class Item < ActiveRecord::Base

  belongs_to :sale, :dependent => :destroy
  has_many :images, :dependent => :destroy

  accepts_nested_attributes_for :images

end

Images Model:

class Image < ActiveRecord::Base
  belongs_to :item, :dependent => :destroy
end
Snead answered 29/3, 2012 at 19:50 Comment(0)
M
9

Create custom methods for validating

In your sales model add something like this:

validate :validate_item_count, :validate_image_count

def validate_item_count
  if self.items.size < 1
    errors.add(:items, "Need 1 or more items")
  end
end

def validate_image_count
  if self.items.images.size < 3
    errors.add(:images, "Need at least 3 images")
  end
end

Hope this helps at all, good luck and happy coding.

Modal answered 29/3, 2012 at 21:10 Comment(5)
ideally name these methods validate_item_count and validate_image_count because this clarifies your intent and that the methods add errors.Rivers
Hm, this isn't working for me on creation of a new record.Derr
Ah, don't worry. I was querying the ActiveRecord association from a third layer of nested_attributes. Got it working by querying the initial nested_attributes instead.Derr
@Derr Glad after 9 years, this is still helpful for people :)Modal
@DonavanWhite Absolutely!Derr
M
4

Another option is using this little trick with the length validation. Although most examples show it being used with text, it will check the length of associations as well:

class Sale < ActiveRecord::Base
   has_many :items,  dependent: :destroy
   has_many :images, through: :items

   validates :items,  length: { minimum: 1, too_short: "%{count} item minimum" }
   validates :images, length: { minimum: 3, too_short: "%{count} image minimum" }
end

You just need to provide your own message as the default message mentions a character count.

Munson answered 7/9, 2013 at 23:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.