Created
January 4, 2013 03:18
-
-
Save kurko/4449645 to your computer and use it in GitHub Desktop.
A "gem" that converts the defined ActiveModel::Validations (validates in Rails' models) to JSON. Also, I created a JS code that invalidate fields based on this generated JSON.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // activeModelValidations | |
| // | |
| // This code is responsible for doing live validations in a form based on a | |
| // JSON object serialized from the Rails' ActiveModel::Validations. This | |
| // prototype interprets this JSON to do the validations. | |
| // | |
| // The entry point is: | |
| // | |
| // activeModelValidations.observe(JSON) | |
| // | |
| // This is responsible for observing any change in the fields specified in the | |
| // JSON object and printing error messages in real time. | |
| // | |
| // The second useful method is: | |
| // | |
| // activeModelValidations.isFormValid(form, JSON) | |
| // | |
| // This method verifies if a given form is valid according to an | |
| // ActiveModel::Validations serialized JSON object. Return true or false. | |
| function activeModelValidations(){ } | |
| var activeModelValidation = new activeModelValidations(); | |
| activeModelValidations.prototype.validators = null; | |
| // | |
| // observe() | |
| // | |
| // Observes any changes in the fields specified in the JSON object. It also | |
| // prints error messages in real time in the invalid fields. | |
| activeModelValidations.prototype.observe = function(validators) { | |
| this.validators = validators; | |
| var _this = this; | |
| $.each(this.validators, function(field, specs){ | |
| $("input[name='"+field+"']").on("focusout", function(){ | |
| _this.validateField(field); | |
| }); | |
| }); | |
| } | |
| // | |
| // isFormValid() | |
| // | |
| // Validates a whole `form`. It adds error messages automatically. | |
| // | |
| // Returns true if all input fields are valid, false otherwise. | |
| activeModelValidations.prototype.isFormValid = function(form, validators) { | |
| var _this = this; | |
| var valid = true; | |
| $.each(validators, function(field, specs){ | |
| if ($(form).find("input[name='"+field+"']").length > 0) | |
| if (!_this.validateField(field)) | |
| valid = false; | |
| }); | |
| return valid; | |
| } | |
| activeModelValidations.prototype.validationCallbacks = function(){ | |
| var jsValidators = new Object(); | |
| jsValidators["presence"] = this.validatePresence; | |
| jsValidators["numericality"] = this.validateNumericality; | |
| jsValidators["length"] = this.validateLength; | |
| return jsValidators; | |
| } | |
| // | |
| // validateField() | |
| // | |
| // Validates a particular input field by name. It also sets the error message. | |
| // | |
| // Returns true if field is valid, false otherwise. | |
| // | |
| activeModelValidations.prototype.validateField = function(field) { | |
| var _this = this; | |
| var specs = this.validators[field]; | |
| if (typeof specs == 'object'){ | |
| for (validator in this.validationCallbacks(this)) { | |
| if (typeof specs[validator] != 'undefined') { | |
| var validatorFunction = this.validationCallbacks()[validator]; | |
| if (!validatorFunction.call(this, field, validator, specs[validator])) | |
| return false; | |
| } | |
| } | |
| } | |
| return true; | |
| }; | |
| // Validation methods corresponding to the following ActiveModel rules: | |
| // | |
| // * presence | |
| // * length | |
| // * numericality | |
| // | |
| // validatePresence() | |
| // | |
| // Validates using ActiveModel's presence algorithm. Current working rules: | |
| // | |
| // - present: checks if a field is present | |
| // | |
| activeModelValidations.prototype.validatePresence = function(fieldName, rule, specs) { | |
| var field = this.getFieldObject(fieldName); | |
| if (specs == true && field.val() == "") { | |
| this.addErrorMessage(field, "Can't be blank."); | |
| return false; | |
| } else | |
| this.removeErrorMessages(field); | |
| return true; | |
| } | |
| // validateLength() | |
| // | |
| // Validates using ActiveModel's length algorithm. Current working rules: | |
| // | |
| // - is: checks if a field has a specific length | |
| // | |
| activeModelValidations.prototype.validateLength = function(fieldName, rule, specs) { | |
| var field = this.getFieldObject(fieldName); | |
| this.removeErrorMessages(field); | |
| // the 'is' options | |
| if (typeof specs["is"] == "number" && field.val().length != specs["is"]) { | |
| var message = "This field has to have "+specs["is"]+" characters" + | |
| " (currently "+field.val().length+")." | |
| this.addErrorMessage(field, message); | |
| return false; | |
| } | |
| // 'minimum' | |
| if (typeof specs["minimum"] == "number" && field.val().length < specs["minimum"]) { | |
| var message = "This field has to have at least " + specs["minimum"] + | |
| " characters (currently " + field.val().length + ")." | |
| this.addErrorMessage(field, message); | |
| return false; | |
| } | |
| // 'maximum' | |
| if (typeof specs["maximum"] == "number" && field.val().length > specs["maximum"]) { | |
| var message = "This field has to have at most " + specs["maximum"] + | |
| " characters (currently " + field.val().length + ")." | |
| this.addErrorMessage(field, message); | |
| return false; | |
| } | |
| return true; | |
| } | |
| // validateNumericality() | |
| // | |
| // Validates ActiveModel numericality. Current working rules: | |
| // | |
| // - integer_only: checks if a field has only numbers | |
| // | |
| activeModelValidations.prototype.validateNumericality = function(fieldName, rule, specs) { | |
| var field = this.getFieldObject(fieldName); | |
| if (specs["only_integer"] && field.val().match(/[^0-9]/)) { | |
| this.addErrorMessage(field, "This field must have only numbers."); | |
| return false; | |
| } else | |
| this.removeErrorMessages(field); | |
| return true; | |
| } | |
| // | |
| // Internal methods | |
| // | |
| activeModelValidations.prototype.getFieldObject = function(fieldName) { | |
| return $("input[name='"+fieldName+"']"); | |
| } | |
| activeModelValidations.prototype.removeErrorMessages = function(field) { | |
| $('div.field_with_error.field_'+field.attr("name")).remove(); | |
| } | |
| activeModelValidations.prototype.addErrorMessage = function(field, message) { | |
| var fieldName = field.attr("name"); | |
| this.removeErrorMessages(field); | |
| var tag = '<div class="field_with_error field_'+fieldName+'">'+message+'</div>'; | |
| field.parent().append(tag); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| module ActiveModel | |
| module ValidationsToJson | |
| # Public: serializes validations to JSON format. | |
| # | |
| # It's useful for client-side validations. | |
| # | |
| # To use this, add to your ActiveModel::Validations compliant class: | |
| # | |
| # extend ActiveModel::ValidationsToJson | |
| # | |
| # Calling validations_to_json() returns a HASH in the following format: | |
| # | |
| # { "field_name" => { | |
| # "presence" => true, | |
| # "length" => { "is" => 16 } | |
| # }, | |
| # "another_field_name => { "presence" => true } | |
| # "number_field => { | |
| # "numericality" => { | |
| # "only_integer" => true | |
| # } | |
| # } | |
| # } | |
| # | |
| def validations_to_json(convert_to_json = true) | |
| validations = validators.each_with_object({}) do |e, validations| | |
| options = {} | |
| if e.kind_of?(ActiveModel::Validations::PresenceValidator) | |
| options[:presence] = true | |
| else | |
| validation_name = e.class.name.split("::").last | |
| validation_name = validation_name.scan(/(.*)Validator/)[0][0].downcase | |
| options[validation_name.to_sym] = e.options.dup | |
| end | |
| merge_options_into_attributes_hash(validations, e.attributes, options) | |
| end | |
| validations = ActiveSupport::JSON.encode(validations) if convert_to_json | |
| validations | |
| end | |
| private | |
| def merge_options_into_attributes_hash(validations, attributes, options) | |
| attributes.each do |attribute| | |
| validations[attribute] = {} unless validations[attribute] | |
| validations[attribute] = validations[attribute].merge(options) | |
| end | |
| end | |
| end | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment