MotionModel
MotionModel copied to clipboard
validate_presence should work for date fields
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
In what case are you expecting an invalid date? Aren't you using a date picker?
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)
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.
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?)
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?
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 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.
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 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
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?
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.
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?
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.
Yep I've not an NSDate, so everything is easy there. Thanks for the help, this makes more sense now :)