Shared validations for multiple fields

eirc edited this page Jul 10, 2012 · 1 revision

You want to have a validation that depends on two (or more) fields.

For example you want the value of a field to be greater than another

class Example
  include ActiveModel::Validations
  include ActiveModel::Conversion
  extend ActiveModel::Naming

  attr_accessor :great_field, :small_field
end

You could use a validate method on the model, but that won't be "client-sided" with the gem. So define a method that returns a combination of the two fields that exposes your validation and validate that:

class Example
  #...

  validates :great_small_fields_diff, :numericality => { :greater_than => 0 }

  def great_small_fields_diff
    great_field - small_field
  end
end

Then in your view render this method in a field that is hidden (but not a hidden_field because that won't be validated).

<%= form_for @example do |f| %>
  <%= f.text_field :great_field %>
  <%= f.text_field :small_field %>
  <%= f.text_field :great_small_fields_diff, :style => 'display: none' %>
<% end %>

And finally with javascript you will need to re-implement the method and run that when you want to validate but also delegate the validation relevant events from the individual fields to the method field.

$('#example_great_small_fields_diff').bind('element:validate:before', function() {
  $(this).val(parseInt($('#example_great_field').val()) -
              parseInt($('#example_small_field').val()));
});

$('#example_great_field, #example_small_field')
  .change(function() { $('#example_great_small_fields_diff').change(); })
  .focusout(function() { $('#example_great_small_fields_diff').focusout(); });