class Changed::Builder

Constants

ARGUMENT_ERROR_EMPTY_KEYS_MESSAGE

Public Class Methods

build(*args) click to toggle source
# File lib/changed/builder.rb, line 8
def self.build(*args)
  new(*args).build
end
new(klass, *keys) click to toggle source
# File lib/changed/builder.rb, line 12
def initialize(klass, *keys)
  raise ArgumentError, ARGUMENT_ERROR_EMPTY_KEYS_MESSAGE if keys.empty?

  @klass = klass
  @keys = keys
end

Public Instance Methods

build() click to toggle source
# File lib/changed/builder.rb, line 19
def build
  define_callbacks_for_associations
  define_after_create_callback
  define_after_update_callback
end

Private Instance Methods

after_create_or_update_for_belongs_to_callback(key, foreign_key, foreign_type, class_name) click to toggle source
# File lib/changed/builder.rb, line 43
def after_create_or_update_for_belongs_to_callback(key, foreign_key, foreign_type, class_name)
  proc do |resource|
    was_associated_id, now_associated_id = resource.saved_change_to_attribute(foreign_key)
    was_associated_type, now_associated_type = resource.saved_change_to_attribute(foreign_type)
    associated_type = resource[foreign_type] || class_name

    if was_associated_id
      resource.audit.associations.build(
        name: key,
        kind: :remove, associated_id: was_associated_id, associated_type: was_associated_type || associated_type
      )
    end

    if now_associated_id
      resource.audit.associations.build(
        name: key, kind: :add,
        associated_id: now_associated_id, associated_type: now_associated_type || associated_type
      )
    end
  end
end
before_add_for_has_many_callback(name) click to toggle source
# File lib/changed/builder.rb, line 77
def before_add_for_has_many_callback(name)
  proc do |_method, resource, associated|
    resource.audit.associations.build(name: name, associated: associated, kind: :add)
  end
end
before_remove_for_has_many_callback(name) click to toggle source
# File lib/changed/builder.rb, line 83
def before_remove_for_has_many_callback(name)
  proc do |_method, resource, associated|
    resource.audit.associations.build(name: name, associated: associated, kind: :remove)
  end
end
define_after_create_callback() click to toggle source
# File lib/changed/builder.rb, line 99
def define_after_create_callback
  keys = @keys
  @klass.after_create do |resource|
    audit = resource.audit
    audit.track(Audit::Event::CREATE, keys)
    audit.save! if audit.anything?
  end
end
define_after_update_callback() click to toggle source
# File lib/changed/builder.rb, line 108
def define_after_update_callback
  keys = @keys
  @klass.after_update do |resource|
    audit = resource.audit
    audit.track(Audit::Event::UPDATE, keys)
    audit.save! if audit.anything?
  end
end
define_callbacks_for_associations() click to toggle source
# File lib/changed/builder.rb, line 27
def define_callbacks_for_associations
  @keys.each do |key|
    association = @klass.reflect_on_association(key)
    case association
    when ActiveRecord::Reflection::HasManyReflection,
      ActiveRecord::Reflection::HasAndBelongsToManyReflection,
      ActiveRecord::Reflection::ThroughReflection
      define_callbacks_for_has_many(association)
    when ActiveRecord::Reflection::BelongsToReflection
      define_callbacks_for_belongs_to(association)
    when ActiveRecord::Reflection::HasOneReflection
      define_callbacks_for_has_one(association)
    end
  end
end
define_callbacks_for_belongs_to(association) click to toggle source
# File lib/changed/builder.rb, line 65
def define_callbacks_for_belongs_to(association)
  callback = after_create_or_update_for_belongs_to_callback(
    association.name,
    association.foreign_key,
    association.foreign_type,
    association.class_name
  )

  @klass.after_update callback
  @klass.after_create callback
end
define_callbacks_for_has_many(association) click to toggle source
# File lib/changed/builder.rb, line 89
def define_callbacks_for_has_many(association)
  name = association.name
  @klass.send(:"before_add_for_#{association.name}") << before_add_for_has_many_callback(name)
  @klass.send(:"before_remove_for_#{association.name}") << before_remove_for_has_many_callback(name)
end
define_callbacks_for_has_one(association) click to toggle source
# File lib/changed/builder.rb, line 95
def define_callbacks_for_has_one(association)
  raise ArgumentError, "unsupported reflection '#{association.name}'"
end