3

I have a model Order with the price attribute.

There are few Order records in the database without a price attribute(nil value) which was imported from the old database. There are less than 20 invalid records like this.

Now the price attribute is mandatory.

I need to add a presence validation of the price and preserve the old records. I can't set the nil values to zero or some random values.

I have some crazy ideas about the conditional validation on the basis of the timestamp or even a list of "permitted" ids.

Something like this:

PERMITTED_IDS = [4, 8, 15, 16, 23, 42]
validates :price, presence: true, if: -> { |order| PERMITTED_IDS.exclude?(order.id) } 

Is there any nice and convenient way for that?

freemanoid
  • 14,592
  • 6
  • 54
  • 77

2 Answers2

3

Use on: :create

The following will only validate when the model is created.

validates :price, presence: true, on: :create

However, can't you just use allow_nil: true:

validates :price, presence: true, allow_nil: true
j-dexx
  • 10,286
  • 3
  • 23
  • 36
  • `allow_nil` is ignored by `presence` validator, I need the validation for all the normal actions (save, initialize) as well – freemanoid Jul 23 '14 at 08:55
0

I would add a boolean imported attribute to the Order class, setting it to true for old records upon import. This allows you to skip validations for these records easily:

validates :price, presence: true, unless: :imported?

UPDATE

Stefan: Are old/imported records editable?

freemanoid: @Stefan yes, but I can't set the price to zero for them.

The above solution is not an option because it would allow a nil price for all old records.

You could use a custom validation that requires a price for new records, but allows nil when updating records if the price was already nil. Something like:

validates :price, presence: true,
                  on: :create

validates :price, presence: true,
                  on: :update,
                  unless: Proc.new { |o| p.price_was.nil? }
Stefan
  • 109,145
  • 14
  • 143
  • 218