diff --git a/app/assets/javascripts/judge.js b/app/assets/javascripts/judge.js index e9a413e..40d963f 100644 --- a/app/assets/javascripts/judge.js +++ b/app/assets/javascripts/judge.js @@ -256,7 +256,12 @@ judge.eachValidators = { // ActiveModel::Validations::PresenceValidator presence: function(options, messages) { - return closed(this.value.length ? [] : [messages.blank]); + if (this.type === 'radio') { + var is_selected = root.document.querySelectorAll('[name="'+this.name+'"]:checked').length; + return closed(is_selected ? [] : [messages.blank]); + } else { + return closed(this.value.length ? [] : [messages.blank]); + } }, // ActiveModel::Validations::LengthValidator diff --git a/spec/javascripts/judge-spec.js b/spec/javascripts/judge-spec.js index 33fdeaa..11353f1 100644 --- a/spec/javascripts/judge-spec.js +++ b/spec/javascripts/judge-spec.js @@ -260,6 +260,25 @@ describe('judge', function() { el.value = 'foo'; expect(validator({}, { blank: 'Must not be blank' })).toBeValid(); }); + it('returns invalid Validation if radio has no selection', function() { + el.type = 'radio' + el.name = 'radio_group' + el.value = 'option1' + // eachValidators.presence for radio btns rely on querySelectorAll + // so we have to add the el to the body + document.body.appendChild(el); + expect(validator({}, { blank: 'Must not be blank' })).toBeInvalid(); + }); + it('returns valid Validation if radio has selection', function() { + el.type = 'radio' + el.name = 'radio_group' + el.value = 'option1' + el.checked = true; + // eachValidators.presence for radio btns rely on querySelectorAll + // so we have to add the el to the body + document.body.appendChild(el); + expect(validator({}, { blank: 'Must not be blank' })).toBeValid(); + }); }); describe('length', function() {