module DestinationErrors

There are three steps to implementing this module in a class:

Setup 1: include DestinationErrors and set error_surfaces

include DestinationErrors
# Usage: set explicitly in each class
#        individual error surfaces can be nil, it's safe.
has_error_surfaces [nil, :lead, :user]

# a simple default with only one surface, nil, where the errors
# accumulate on the object including this module would be:
#   has_error_surfaces [nil]

Setup 2: (optional)

def initialize
  # choose one of the surfaces to aggregate errors onto, with nil indicating self.
  @surface_errors_on = nil
end

Setup 3: call move_all_errors_to_destination after errors may exist on the error_surfaces

def finalize
  move_all_errors_to_destination
  self # if you want chainability return self
end

Constants

VERSION

Public Class Methods

included(base) click to toggle source
# File lib/destination_errors.rb, line 36
def self.included(base)
  base.prepend(Initializer)
  base.extend(ClassMethods)
  base.include(DestinationErrors::ActiveModelIntegration)
  base.include(DestinationErrors::UniqueErrors)
  base.class_eval do
    attr_accessor :errors_finalized
    attr_accessor :surface_errors_on
    class_attribute :error_surfaces
  end
end

Public Instance Methods

error_destination() click to toggle source

dynamically access the surface where errors are being aggregated

# File lib/destination_errors.rb, line 69
def error_destination
  @error_destination = error_destination_is_self? ?
      self :
      self.send(self.surface_errors_on)
end
error_surfaces_clean?() click to toggle source

Checks to see if any errors have been registered on any of the error surfaces but:

1. does not re-run validations
2. does not add or move errors

returns true if any errors are found on any surface or false otherwise

# File lib/destination_errors.rb, line 59
def error_surfaces_clean?
  return false if self.errors.any?
  self.class.error_surfaces.compact.each do |surface|
    return false if errors_on_surface?(surface)
  end
  return false if custom_error_destination_has_errors?
  return true
end

Protected Instance Methods

custom_error_destination_has_errors?() click to toggle source

The error destination is not one of error_surfaces, and is not self, and has errors…

# File lib/destination_errors.rb, line 85
def custom_error_destination_has_errors?
  !self.class.error_surfaces.include?(surface_errors_on) &&
      !error_destination_is_self? &&
          errors_on_surface?(surface_errors_on)
end
error_destination_is_self?() click to toggle source
# File lib/destination_errors.rb, line 129
def error_destination_is_self?
  surface_errors_on.nil? || !self.send(surface_errors_on)
end
errors_on_surface?(surface) click to toggle source
# File lib/destination_errors.rb, line 119
def errors_on_surface?(surface)
  self.send(surface) && self.send(surface).errors.any?
end
move_all_errors_to_destination() click to toggle source
# File lib/destination_errors.rb, line 91
def move_all_errors_to_destination
  return false if self.errors_finalized
  self.error_surfaces.each do |surface|
    move_errors_from_surface_to_destination_if_needed(surface)
  end
  self.errors_finalized = true
end
move_error_to_destination(key, *message_array) click to toggle source
# File lib/destination_errors.rb, line 133
def move_error_to_destination(key, *message_array)
  if error_destination.respond_to?(key)
    add_errors_uniquely(key, *message_array)
  elsif key == :base
    add_errors_uniquely(:base, *message_array)
  else
    add_errors_uniquely(:base, *message_array.map {|message| "#{key} #{message}"})
  end
end
move_errors_from_surface?(surface) click to toggle source
# File lib/destination_errors.rb, line 111
def move_errors_from_surface?(surface)
  if surface.nil?
    !error_destination_is_self? && errors && errors.any?
  else
    (surface_errors_on.to_s != surface.to_s) && errors_on_surface?(surface)
  end
end
move_errors_from_surface_to_destination_if_needed(surface) click to toggle source
# File lib/destination_errors.rb, line 99
def move_errors_from_surface_to_destination_if_needed(surface)
  if move_errors_from_surface?(surface) && error_destination
    (
      surface.nil? ?
        errors.messages :
        self.send(surface).errors.messages
    ).each do |key, message_array|
      move_error_to_destination(key, *message_array)
    end
  end
end