ibanez270dx
6/19/2016 - 9:34 AM

Snippets from my blog post "Better Conditional Validations in Rails"

Snippets from my blog post "Better Conditional Validations in Rails"

def conditionally_validate(attribute, options=nil)
  unless options.nil? 
    unless options[:if].nil?
      options[:if] = "#{options[:if]} && validated_fields.include?(:#{attribute})"
      validates attribute, options
    else
      validates attribute, options.merge(if: "validated_fields.include?(:#{attribute})")
    end
  else
    validate :"validate_#{attribute}", if: "validated_fields.include?(:#{attribute})"
  end
end
def conditionally_validate(attribute, options=nil)
  unless options.nil? 
    unless options[:if].nil?
      options[:if] = "#{options[:if]} && validated_fields.include?(:#{attribute})"
      validates attribute, options
    else
      validates attribute, options.merge(if: "validated_fields.include?(:#{attribute})")
    end
  end
end
def conditionally_validate(attribute, options=nil)
  unless options.nil? 
    validates attribute, options.merge(if: "validated_fields.include?(:#{attribute})")
  end
end
class User < ActiveRecord::Base
  include ConditionalValidations

  conditionally_validate :name, presence: true
  conditionally_validate :email, format: { with: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/ }, length: { maximum: 100 }
end
#pathway2_controller.rb

def create_user
  user = User.new params[:user]
  user.validated_fields = [ :name ]
  user.save
end
#pathway1_controller.rb

def create_user
  user = User.new params[:user]
  user.validated_fields = [ :name, :email ]
  user.save
end
module ConditionalValidations
  attr_accessor :validated_fields
end

ActiveRecord::Base.extend ConditionalValidations
class User < ActiveRecord::Base
  include ConditionalValidations

  # ... your model code
end
def fields_valid?(fields)
  # are there any existing errors?
  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.

  # run .valid? to repopulate @errors if need be. Otherwise, clear them. 
  (original_errors > 0) ? self.valid? : self.errors.clear
  return validity
end
user.fields_valid? [ :name, :email, :phone ]   # true or false
user = User.new(name: 'Jeff', email: 'blah')

user.validated_fields = [:name, :email]
user.save     # false

user.validated_fields = [:name]
user.save     # true
class Person < ActiveRecord::Base
  validates :surname, presence: true, if: "name.nil?"
end