Laziness and Stupidity, Part 2
Last time, I presented a couple screenshots from a recent user experience I had on the web. (If you missed it, go back and read it real quick, or the rest of this post won’t make much sense).
Thanks to everyone who responded. It was fun to see the variety of approaches that people took to solving the problem of cleaning up the “miles driven” field automatically.
For what it’s worth, the approach I would have taken would have been to use the before_validation helper in the model, as a couple of people suggested (hence the words “model validation” in the original article title). There were a few suggestions that seemed to imply that the cleanup would happen in the controller, but I don’t think that’s the right place. By making the model responsible for its data, this logic becomes more reusable and it becomes easier to attach error messages as needed.
For the curious, to just remove commas and ignore any digits after a decimal point, this will work:
miles.delete(',').to_i
but this doesn’t remove any other non-digit characters, so a value like “A123.4” will become zero. This is one of those rare moments where C# is a bit better, as Int32.Parse would come in real handy here.
But rather than try to come up with a more complicated regular expression to get rid of letters and other invalid characters, I would simply use another model validation helper to enforce a greater-than-zero value:
validates_numericality_of :miles, :greater_than => 0, :message => "must be higher than zero"
I guess my point is, I think sometimes we try to do too much. Rails is a pretty big framework and often has something built-in to make your job easier than you think.



BigDecimal("A123.4"[/[0-9\.\,]+/])Just being snarky. ;-) Great series. Keep it up!
But c# being better for this… blasphemy! Int32.TryParse() FTL. :-)
Please don’t do “greater_than => 0”—now your site is unusable for people with brand new cars that have been driven less than a mile (mostly occurs when cars are delivered by land. Right onto a truck, and right off at a dealership.
In the last post I didn’t really specify if the logic should go into the controller or the model… the challenge was pretty simple, so I just delivered the relevant code but sorry if I gave you the wrong impression. :)
yeah, man, the regex on this one is pretty small and if you want to just get to the number I just use…
miles.gsub(/\D/,”“).to_i
that’s just as simple as the outbound signature employed by TryParse (which I’ve never liked).
BTW- I really like this series and can’t wait to see the next one!
@Sam: Excellent… totally overlooked BigDecimal.
@Leon: Actually, that regex will turn “1.5” into 15, whereas we’d probably want just 1 (or 2, if we care about rounding, but I don’t). So you need to throw way anything after the decimal first; and before you know it you could be in regex write-only land. As for the next in the series… stay tuned. It shouldn’t be long before I come across something else I can complain about. :-)
while I see no problems with the before_filter approach, could you say why you chose that over writing your own miles= method?
Mike, I probably can’t give a convincing argument one way or the other… I often do override attributes in the way you suggest. I guess for this kind of thing – just cleaning up user-entered data – it just feels like a validation-related concern. I’d probably use a custom attribute setter when I’d need to trigger some other kind of action or do something fancier. It’s probably just a matter of taste, I suppose.
Our faculties constitute the whole content for, thus, the paralogisms of pure reason.