class ActiveType::NestedAttributes::Association

Public Class Methods

new(owner, target_name, options = {}) click to toggle source
# File lib/active_type/nested_attributes/association.rb, line 11
def initialize(owner, target_name, options = {})
  options.assert_valid_keys(*valid_options)

  @owner = owner
  @target_name = target_name.to_sym
  @allow_destroy = options.fetch(:allow_destroy, false)
  @reject_if = options.delete(:reject_if)
  @options = options.dup

  @index_errors = case
                  when ActiveRecord::VERSION::MAJOR < 5
                    @options[:index_errors]
                  when ActiveRecord::VERSION::MAJOR < 7
                    @options[:index_errors] || ActiveRecord::Base.index_nested_attribute_errors
                  else
                    @options[:index_errors] || ActiveRecord.index_nested_attribute_errors
                  end
end

Public Instance Methods

assign_attributes(parent, attributes) click to toggle source
# File lib/active_type/nested_attributes/association.rb, line 30
def assign_attributes(parent, attributes)
  raise NotImplementedError
end
save(parent) click to toggle source
# File lib/active_type/nested_attributes/association.rb, line 34
def save(parent)
  keep = assigned_children(parent)
  changed_children(parent).each do |child|
    if child.marked_for_destruction?
      child.destroy if child.persisted?
      keep.delete(child)
    else
      child.save(:validate => false) or raise ActiveRecord::Rollback
    end
  end
  assign_children(parent, keep)
end
validate(parent) click to toggle source
# File lib/active_type/nested_attributes/association.rb, line 47
def validate(parent)
  changed_children(parent).each_with_index do |child, index|
    add_errors_to_parent(parent, child, index) unless child.valid?
  end
end

Private Instance Methods

add_child(parent, child_or_children) click to toggle source
# File lib/active_type/nested_attributes/association.rb, line 55
def add_child(parent, child_or_children)
  raise NotImplementedError
end
add_errors_to_parent(parent, child, index) click to toggle source
# File lib/active_type/nested_attributes/association.rb, line 132
def add_errors_to_parent(parent, child, index)
  if Gem::Version.new(ActiveRecord::VERSION::STRING) >= Gem::Version.new("6.1")
    child.errors.each do |error|
      attribute = translate_error_attribute(error.attribute, index)
      parent.errors.add(attribute, error.message)
    end
  else
    child.errors.each do |attribute, message|
      attribute = translate_error_attribute(attribute, index)
      parent.errors.add(attribute, message)
      parent.errors[attribute].uniq!
    end
  end
end
assign_children(parent, children) click to toggle source
# File lib/active_type/nested_attributes/association.rb, line 63
def assign_children(parent, children)
  raise NotImplementedError
end
assigned_children(parent) click to toggle source
# File lib/active_type/nested_attributes/association.rb, line 59
def assigned_children(parent)
  Array.wrap(parent[@target_name])
end
build_child(parent, attributes) click to toggle source
# File lib/active_type/nested_attributes/association.rb, line 71
def build_child(parent, attributes)
  build_scope(parent).new(attributes)
end
build_scope(parent) click to toggle source
# File lib/active_type/nested_attributes/association.rb, line 79
def build_scope(parent)
  scope_for(parent, :build_scope) || scope(parent)
end
changed_children(parent) click to toggle source
# File lib/active_type/nested_attributes/association.rb, line 67
def changed_children(parent)
  assigned_children(parent).select(&:changed_for_autosave?)
end
derive_class_name() click to toggle source
# File lib/active_type/nested_attributes/association.rb, line 95
def derive_class_name
  raise NotImplementedError
end
fetch_child(parent, id) click to toggle source
# File lib/active_type/nested_attributes/association.rb, line 99
def fetch_child(parent, id)
  assigned = assigned_children(parent).detect { |r| r.id == id }
  return assigned if assigned

  if child = find_scope(parent).find_by_id(id)
    add_child(parent, child)
    child
  else
    raise RecordNotFound, "could not find a child record with id '#{id}' for '#{@target_name}'"
  end
end
find_scope(parent) click to toggle source
# File lib/active_type/nested_attributes/association.rb, line 83
def find_scope(parent)
  scope_for(parent, :find_scope) || scope(parent)
end
reject?(parent, attributes) click to toggle source
# File lib/active_type/nested_attributes/association.rb, line 116
def reject?(parent, attributes)
  result = case @reject_if
  when :all_blank
    attributes.all? { |key, value| key == '_destroy' || value.blank? }
  when Proc
    @reject_if.call(attributes)
  when Symbol
    parent.method(@reject_if).arity == 0 ? parent.send(@reject_if) : parent.send(@reject_if, attributes)
  end
  result
end
scope(parent) click to toggle source
# File lib/active_type/nested_attributes/association.rb, line 75
def scope(parent)
  scope_for(parent, :scope) || derive_class_name.constantize
end
scope_for(parent, key) click to toggle source
# File lib/active_type/nested_attributes/association.rb, line 87
def scope_for(parent, key)
  parent._nested_attribute_scopes ||= {}
  parent._nested_attribute_scopes[[self, key]] ||= begin
    scope = @options[key]
    scope.respond_to?(:call) ? parent.instance_eval(&scope) : scope
  end
end
translate_error_attribute(attribute, index) click to toggle source
# File lib/active_type/nested_attributes/association.rb, line 147
def translate_error_attribute(attribute, index)
  @index_errors ? "#{@target_name}[#{index}].#{attribute}" : "#{@target_name}.#{attribute}"
end
truthy?(value) click to toggle source
# File lib/active_type/nested_attributes/association.rb, line 111
def truthy?(value)
  @boolean_type_caster ||= TypeCaster.get(:boolean)
  @boolean_type_caster.type_cast_from_user(value)
end
valid_options() click to toggle source
# File lib/active_type/nested_attributes/association.rb, line 128
def valid_options
  [:build_scope, :find_scope, :scope, :allow_destroy, :reject_if]
end