NoDisplayName
NoDisplayName

Reputation: 15736

How to validate an attribute only if it exists?

I have a lot of models with many different attributes that are shared between them, and so I have to validate them all and thats where I am having a problem. If I group all attributes that are always used together and put their validations in a separated module, I end up with like 20 modules, which just doesnt seem right... Also I thought about putting attrs validations in only like 2-3 modules grouping them logically, like one module for location attrs, other is for options and etc and additing to all of them the IF condition the following way:

validates :city,
presence: true,
length: {minimum: 5},
if: Proc.new {|p| p.respond_to?(:city)}

and it looks like it works but repeating this condition to every validation method is just even more wrong than having a bunch of modules, so the question is, how do I do it right?

Edit: Example: Imagine you have 3 models: Car, Truck and Bicycle and their attrs are:

Car -> attr_1, attr_3

Truck -> attr_2, attr_3

Bicycle -> attr_1, attr_2

and so u can put validation of every attr to its module and include it to the clases that have this attribute, so u dont have to repeat it... ( thats where I end up with 20 modules) or u can create only one module with 3 validations like the following:

validates :attr_1, length: {minimum: 2}, if: Proc.new {|p| p.respond_to?(:attr_1)}
validates :attr_2, presence: true, if: Proc.new {|p| p.respond_to?(:attr_2)}
validates :attr_3, inclusion: {in: 1..5}, if: Proc.new {|p| p.respond_to?(:attr_3)}

which seems to be more ugly ... So I need to find some compromise here ...

Upvotes: 0

Views: 1134

Answers (2)

Max Williams
Max Williams

Reputation: 32933

Remember you're just using ruby code here, there's nothing magical going on. So you can do a loop:

[:attr1, :attr2, :attr3].each do |att|
  validates att, presence: true, length: {minimum: 5}, if: Proc.new {|p| p.respond_to?(att)}
end

Upvotes: 1

Taryn East
Taryn East

Reputation: 27747

Ok... so you have multiple models with a set of related attribute (and validations) on them>

some options are:

  1. use a module that is included in each of the models
  2. extract the attributes out into a model of its own (with its own attributes and validations) and is polymorphically associated to each of the related models
  3. if you are using the latest version of rails, have a look at concerns - which is a better way of doing (1)

if there really are 20 different groups of things... then create 20. But if groups of these things are always together in every model that uses them... you can put them into one spot together (and use code like Max's suggestion to make it shorter to read)

Upvotes: 1

Related Questions