Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ActiveRecord - replace model validation error with warning

I want to be able to replace a field error with a warning when saving/updating a model in rails. Basically I want to just write a wrapper around the validation methods that'll generate the error, save the model and perhaps be available in a warnings hash (which works just like the errors hash):

class Person < ActiveRecord::Base
  # normal validation
  validates_presence_of :name

  # validation with warning
  validates_numericality_of :age, 
                            :only_integer => true, 
                            :warning => true # <-- only warn
end

>>> p = Person.new(:name => 'john', :age => 2.2)
>>> p.save
=> true # <-- able to save to db
>>> p.warnings.map { |field, message| "#{field} - #{message}" }
["age - is not a number"] # <-- have access to warning content

Any idea how I could implement this? I was able to add :warning => false default value to ActiveRecord::Validations::ClassMethods::DEFAULT_VALIDATION_OPTIONS By extending the module, but I'm looking for some insight on how to implement the rest. Thanks.

like image 635
sa125 Avatar asked Jul 27 '10 09:07

sa125


3 Answers

The validation_scopes gem uses some nice metaprogramming magic to give you all of the usual functionality of validations and ActiveRecord::Errors objects in contexts other than object.errors.

For example, you can say:

validation_scope :warnings do |s|
  s.validates_presence_of :some_attr
end

The above validation will be triggered as usual on object.valid?, but won't block saves to the database on object.save if some_attr is not present. Any associated ActiveRecord::Errors objects will be found in object.warnings.

Validations specified in the usual manner without a scope will still behave as expected, blocking database saves and assigning error objects to object.errors.

The author has a brief description of the gem's development on his blog.

like image 193
KenB Avatar answered Nov 19 '22 16:11

KenB


I don't know if it's ready for Rails 3, but this plugin does what you are looking for:

http://softvalidations.rubyforge.org/

Edited to add:

To update the basic functionality of this with ActiveModel I came up with the following:

#/config/initializer/soft_validate.rb:
module ActiveRecord
  class Base
    def warnings
      @warnings ||= ActiveModel::Errors.new(self)
    end
    def complete?
      warnings.clear
      valid?
      warnings.empty?
    end
  end
end

#/lib/soft_validate_validator.rb
class SoftValidateValidator < ActiveModel::EachValidator
  def validate(record)
    record.warnings.add_on_blank(attributes, options)
  end
end

It adds a new Errors like object called warnings and a helper method complete?, and you can add it to a model like so:

class FollowupReport < ActiveRecord::Base
  validates :suggestions, :soft_validate => true
end
like image 36
kweerious Avatar answered Nov 19 '22 17:11

kweerious


I made my own gem to solve the problem for Rails 4.1+: https://github.com/s12chung/active_warnings

class BasicModel
  include ActiveWarnings

  attr_accessor :name
  def initialize(name); @name = name; end

  warnings do
    validates :name, absence: true
  end
end

model = BasicModel.new("some_name")
model.safe? # .invalid? equivalent, but for warnings
model.warnings # .errors equivalent
like image 44
s12chung Avatar answered Nov 19 '22 17:11

s12chung