Ruby on Rails allows for plugins to extend its functionality. My first attempt at one is nothing special but I am going to blog about it anyway 😀
I needed a way to check if a number is within a range before saving a record to the database. Rails has a number of good validations built in, but not one that does that. In two or three hours, I was able to piece together a simple plugin that adds “validates_range_of” to my AR models. The code is a little ugly until I can get Greg to install a syntax highlighting plugin for this blog.
module ActiveRecord module Validations module ClassMethods def validates_range_of(*attrs) options = { :on => :save } options.update(attrs.pop) if attrs.last.is_a?(Hash) attrs.flatten! unless options[:message] if options[:maximum] && options[:minimum] options[:message] = 'must be betweeen ' + options[:minimum].to_s + ' and ' + options[:maximum].to_s elsif options[:maximum] options[:message] = 'must be less than or equal to ' + options[:maximum].to_s elsif options[:minimum] options[:message] = 'must be greater than or equal to ' + options[:minimum].to_s else raise ArgumentError, 'Range unspecified. Specify the :maximum and/or :minimum.' end end validates_numericality_of( attrs, options ) validates_each(attrs, options) do |record, attr_name, value| if ((!options[:maximum].nil?) && (!options[:minimum].nil?)) && (value > options[:maximum] || value < options[:minimum]) record.errors.add( attr_name, options[:message] ) elsif (!options[:maximum].nil?) && value > options[:maximum] record.errors.add( attr_name, options[:message] ) elsif (!options[:minimum].nil?) && value < options[:minimum] record.errors.add( attr_name, options[:message] ) end end end end end end |
As you can see this plugin extends AR::Validations. So my models can use validates_range_of to check minimum and maximum values. Let’s look at the BJCP Scoresheet I needed it for:
class BjcpScoresheet < ActiveRecord::Base belongs_to :brew_session validates_associated :brew_session validates_range_of :brew_session_id, { :minimum => 1, :message => 'does not belong to a brew session' } validates_range_of :aroma_score, { :minimum => 1, :maximum => 12, :only_integer => true } validates_range_of :appearance_score, { :minimum => 1, :maximum => 3, :only_integer => true } validates_range_of :flavor_score, { :minimum => 1, :maximum => 20, :only_integer => true } validates_range_of :mouthfeel_score, { :minimum => 1, :maximum => 10, :only_integer => true } validates_range_of :impression_score, { :minimum => 1, :maximum => 10, :only_integer => true } |
How nice – reusable user input validation.
–Dean
oooo a brewer and ruby programmer… You should make something to compete with ProMash and Beermith! Open Source FTW!
Hi Tony,
😀 BrewSession will compete with Promash and Beersmith, except we’re keeping it to ourselves. It will be free to use however. There is an open-source brewing software movement starting at http://www.beerhackers.com/ and we’re going to work with them to inter-operate.
–Dean