MotionModel icon indicating copy to clipboard operation
MotionModel copied to clipboard

validate_presence should work for date fields

Open robj opened this issue 11 years ago • 14 comments

It is not immediately apparent from docs it only supports Numeric/String

my custom validator for the interim:

def validate_date_presence(field, value, setting)
  if(value.is_a?(Time || Date))
    return true
  else
    return false
  end
end

robj avatar Dec 05 '13 03:12 robj

In what case are you expecting an invalid date? Aren't you using a date picker?

sxross avatar Dec 05 '13 18:12 sxross

In this case I am creating models from a JSON API. Validations are to ensure I only have valid models even in the case something is not correct server side (ie. I get sent a nil date)

robj avatar Dec 05 '13 21:12 robj

IIRC, you should be able to use before_validation(sender) for this. You may disagree with this approach, but take it out for a spin.

def before_validation(sender)
  !sender.create_date.nil?
end

or something like that. Your validation is equally valid and if you would like to submit a pull request with a spec, that would be great.

sxross avatar Dec 05 '13 21:12 sxross

Thanks, As a simple change to validate_presence, would this suffice?

def validate_presence(field, value, setting) if(value.is_a?(Numeric || Time || Date)) return true elsif value.is_a?(String) || value.nil?

(or just including Time, as I presume all date casts are to Time?)

robj avatar Dec 05 '13 21:12 robj

Let's take a step back. Say there are two ways of populating your model. Way 1 is that the user enters info on their iPhone. Further, say that your model contains start time and end time, so it's ok to start something without ending it. That implies that for Way 1, a nil date is ok. Way 2 is to slurp it off the server, in which case, nil dates are not ok.

So the default "validate this way all the time" ala Rails is not actually perfect for this kind of thing. I don't know if you have this requirement, but it's something worth considering.

Comments?

sxross avatar Dec 05 '13 22:12 sxross

I'd say in the case a nil date is OK, then it's counterintuitive to use a presence validator at all?

On 6 Dec 2013, at 9:02 am, "s.ross" [email protected] wrote:

Let's take a step back. Say there are two ways of populating your model. Way 1 is that the user enters info on their iPhone. Further, say that your model contains start time and end time, so it's ok to start something without ending it. That implies that for Way 1, a nil date is ok. Way 2 is to slurp it off the server, in which case, nil dates are not ok.

So the default "validate this way all the time" ala Rails is not actually perfect for this kind of thing. I don't know if you have this requirement, but it's something worth considering.

Comments?

— Reply to this email directly or view it on GitHub.

robj avatar Dec 05 '13 23:12 robj

@robj In Rails that would be validates_presence_of :created_at, allow_nil: true, to disallow blanks. If you want to enforce a date format or a parseable date format, that would be a custom validator and possibly an overridden setter method that parses dates if they are strings inbound.

DougPuchalski avatar Dec 05 '13 23:12 DougPuchalski

currently validates_presence fails validation if the field is not of a numeric or string type. This seems to violate the principle of least surprise if it is not usable on all available field types.

On 6 Dec 2013, at 10:39 am, Doug Puchalski [email protected] wrote:

@robj In Rails that would be validates_presence_of :created_at, allow_nil: true, to disallow blanks. If you want to enforce a date format or a parseable date format, that would be a custom validator and possibly an overridden setter method that parses dates if they are strings inbound.

— Reply to this email directly or view it on GitHub.

robj avatar Dec 05 '13 23:12 robj

@robj You might want to use a format validator. From the spec:

validate      :some_day, :format => /\A\d?\d-\d?\d-\d\d\Z/

This would fail if nil and only succeed if the date were formatted as specified (you would probably want to use ISO dates, judging from your earlier issue).

I know you've already read this, but the relevant portion of the documentation regarding custom validators is:

https://github.com/sxross/MotionModel#validation-methods

sxross avatar Dec 06 '13 17:12 sxross

This has just had me going round in circles too until I decided to remove my validations. I tried validating the presence of a date and an array, both of which failed even though they were present. I was going to call the following line on each field change in my ViewController to disable the save button until all the required fields were filled in. saveButton.enabled = myNewObject.valid? This seems like sensible logic to me?

pixlwave avatar Mar 18 '15 18:03 pixlwave

I'm not sure this will work. The object does not have any data until you put it there. If you aren't doing that as the user enters it, you can't validate against it. Further, once you assign to a model field of type date or type array, MotionModel casts the value to it's Ruby type. So, presence validates against nil or length == 0. The latter case may work for array but not for date. This may not be a model issue.

sxross avatar Mar 18 '15 18:03 sxross

Ok so in which case, if I'm migrating some code from CDQ, I'd implement datetime :mydate, optional: false with a format validation as shown above? And for an array, I probably need to make a validation with a block of some sort right?

pixlwave avatar Mar 18 '15 19:03 pixlwave

I'm not sure about the optional: part. I think I'd go with default: if you want to set it to something. If you are migrating from CDQ will you have a string or an NSDate. MotionModel will recognize NSDate and copy it over. If it's a string, it will try to use a NSDataDetector to parse it.

For the array, presence: looks at the length. Once you have assigned the array to your model, it will know the length and be able to validate. So you could as easily say: length: [4..12] or something like that.

Remember, validations are not necessarily for doing on-the-fly form validations -- more so to ensure data integrity. There's no reason not to use them for input validations, but don't forget to roll back your transaction before moving on if the user cancels.

The main place I'm looking is motion/validatable.rb. It's pretty straightforward code.

sxross avatar Mar 18 '15 19:03 sxross

Yep I've not an NSDate, so everything is easy there. Thanks for the help, this makes more sense now :)

pixlwave avatar Mar 18 '15 20:03 pixlwave