One of, a pocket case
Friday, June 30th, 2006Another one of our snippets of code (all collected in a ‘private’ plugin called, surprisingly, ’snippets’) is one_of.
Suppose you have an html form, with a select that let your users specify the sort order for your index page. Said order can take a value of “name”, “name desc”, “date” or “date desc”. The more observant among you are probably yelling “SQL injection!!!, SQL injection!!!”, because even if your select only has those four options, nothing can prevent a malicious script kiddie to modify the request and ask for sort_order=your momma or perhaps sort_order=name; delete from users.
So smart web developers (or dumb web developers smart enough to remember when their sites got hacked because of a SQL injection) validate anything that comes from the outside world.
Our snippet, one_of, provides a simple way to do a very common validation: making sure a value is one of a given set of possible values.
class Object
# Makes sure the value is "one of" the list given,
# otherwise returns the first value from the list
def one_of(*args)
args = args[0] if args.size == 1 and args[0].kind_of? Array
(args.include?(self) && self) || args[0]
end
end
It’s use is exemplified, for example, in the following examples:
query[:sort] = params[:sort_order].one_of("name", "name desc",
"date", "date desc")
answer = answer.one_of("yes", "no")
answer = nil.one_of("yes", "no") # => "yes"
This method serves it’s purpose well, so we haven’t had a need to enhance it. But I can easily think of a couple of improvements, making it more case-like.
class Object
# Makes sure the value is "one of" the list given,
# otherwise returns the first value from the list
def one_of(*args)
args = args[0] if args.size == 1 and args[0].kind_of? Array
args.each do |arg|
return (arg.kind_of?(Regexp) ? $1 : self) if arg === self
end
args.first
end
end
See? Now you can do thinks like:
"abc".one_of(String, Numeric) # => "abc"
"abc".one_of("none", /([bc]+)/) # => "bc"
It works almost like a pocket-sized version of case, with the default being first instead of last.
But be careful. Since the default value is the first one in the array, you might end up with a Class object, or a Regexp.