Last active
April 10, 2018 11:31
-
-
Save ibanez270dx/4955453 to your computer and use it in GitHub Desktop.
A simple module that allows validation of only certain attributes of any given model. Created for CoverHound.com.
This file contains 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
# | |
# 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 |
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
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.....