Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
A simple module that allows validation of only certain attributes of any given model. Created for CoverHound.com.
#
# At CoverHound, we use conditional validations all over the form. However, there is no proper way to do
# this in Rails. Instead, we can provide an array of attributes (validated_fields attribute)
# and ensure they are the only ones to get validated.
#
module ConditionalValidations
attr_accessor :validated_fields
def field_is_required?(field)
unless validated_fields.blank?
validated_fields.include?(field)
end
end
def conditionally_validate(attribute, options=nil)
unless options.nil?
# Passing options for built-in validators
# http://guides.rubyonrails.org/active_record_validations_callbacks.html#validation-helpers
unless options[:if].nil?
options[:if] = "#{options[:if]} && field_is_required?(:#{attribute})"
validates attribute, options
else
validates attribute, options.merge(if: "field_is_required?(:#{attribute})")
end
else
# Block validation
# will initiate a validator on attribute using a method called validate_#{attribute}
validate :"validate_#{attribute}", if: "field_is_required?(:#{attribute})"
end
end
def fields_valid?(fields)
# Note that when validations are run, class variable @errors changes. As such, we have
# to keep track of whether there were errors originally and repopulate them as necessary.
original_errors = self.errors.messages.count
mock = self.dup # duplicate the model in a non-persisted way.
mock.validated_fields = fields # ...tell model what fields to validate.
validity = mock.valid? # run validations and change @errors.
# If there were errors on the original model, run valid? so that it populates @errors.
# Otherwise, remove any errors left over from the mock run.
(original_errors > 0) ? self.valid? : self.errors.clear
return validity
end
end
ActiveRecord::Base.extend ConditionalValidations
@betjaminrichards
Copy link

betjaminrichards commented Mar 5, 2014

I love this module. It's very useful. However I wonder if you could help me adapt it to my specific use case?

I have it working fine in a standard form scenario, but what I'm trying to do is set the attributes to validate on a child object through the accepts_nested_attributes_for method.

The problem is that I can put the following in the update action for my parents class in the controller:

@child.validated_fields = [ :title, :email ]

But because the attributes are being pass through the childs_attributes option in the parameters hash it isn't getting picked up by the Child model.

Can you help? I though about hacking the childs_attributes in the parameters hash but that just feels ugly and not very rails-ish.....

@ibanez270dx
Copy link
Author

ibanez270dx commented Jun 11, 2015

Woah, I just saw this! Sorry I never answered your question -- did you ever find a solution?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment