An update on Judge

I’ve just released Judge 1.5.0 and since it’s been a while since the last update, I thought I’d run through some of the improvements that have been made since version 1.0.0 and also introduce some ideas for future improvements.

gem "judge", "~> 1.5.0"

Callbacks

The various validate() methods now accept callback functions. Yep, real modern. The cool thing about this is that we can handle what happens after validation a little more elegantly. Behold!

watcher.validate([callback])

var watcher = new judge.Watcher(document.getElementById('foo'));
watcher.validate(function(valid, messages, element) {
  element.style.background = valid ? 'green' : 'red';
});

judge.validate(elements, [callback])

// callback is executed once for each input
judge.validate(document.getElementsByTagName('input'), function(valid, messages, element) {
  element.style.background = valid ? 'green' : 'red';
});

judge.store.validate(key, [callback])

judge.store.save('foo', document.getElementById('foo'));
// callback is executed once for each element stored 
// against key 'foo' (in this case just once)
judge.store.validate('foo', function(valid, messages, element) {
  element.style.background = valid ? 'green' : 'red';
});

I18n

Internationalized error messages are sweet. Remember when Rails didn’t do this? Oh man. Bad times. They’re still a bit confusing though. There are a lot of bad custom validator examples sitting around on the web, just waiting to be copied and pasted into some poor, unsuspecting app. Don’t do this:

class FooValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    if value != "foo"
      record.errors[attribute] << "ain't foo"
    end
  end
end

That rogue error message is doing nobody any favours. The errors object has an add method which will handle i18n translation lookup for you:

class FooValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    if value != "foo"
      record.errors.add(attribute, :not_foo)
    end
  end
end

You can read about how the error message is looked up over on rubyonrails.org.

Since Judge is all about porting stuff from server- to client-side for great DRY justice, you can now use declare_messages in your custom EachValidator to specify which messages will be made available to your validation methods on the client-side:

class FooValidator < ActiveModel::EachValidator
  declare_messages :not_foo

  def validate_each(record, attribute, value)
    if value != "foo"
      record.errors.add(attribute, :not_foo)
    end
  end
end

This means that we can access our translated message like this:

judge.customValidators.foo = function(valid, messages, element) {
  console.log(messages.not_foo);
};

Documentation

The Judge docs have been spruced up a little too. Please do let me know if anything is unclear.

The future

I have a few things that I’m planning on adding to Judge in the very near future.

Uniqueness validation

This isn’t currently possible with Judge but given the updates to Engines in Rails >= 3.1, I’m excited about tackling this issue in a clean, unobtrusive way. Watch this space.

Backbone.Model validation

Backbone.js models have a validate method which, with a little extra work, I think could work really nicely with Judge. I’m not settled on how to implement this but I have some vague ideas. Suggestions welcome as always.