class ViewModel::ActiveRecord::UpdateOperation::MutableReferencedCollection

Helper class to wrap the previous members of a referenced collection and provide update operations. No one member may be affected by more than one update operation. Elements removed from the collection are collected as `orphaned_members`.“

Attributes

association_data[R]
blame_reference[R]
free_members_by_indirect_ref[R]
members[R]
orphaned_members[R]
update_context[R]

Public Class Methods

new(association_data, update_context, members, blame_reference) click to toggle source
# File lib/view_model/active_record/update_operation.rb, line 672
def initialize(association_data, update_context, members, blame_reference)
  @association_data = association_data
  @update_context   = update_context
  @members          = members.dup
  @blame_reference  = blame_reference

  @orphaned_members = []

  @free_members_by_indirect_ref = @members.index_by(&:indirect_viewmodel_reference)
end

Public Instance Methods

concat(references) click to toggle source
# File lib/view_model/active_record/update_operation.rb, line 700
def concat(references)
  new_members = claim_or_create_references(references)
  remove_from_members(new_members)
  members.concat(new_members)
end
insert_after(relative_to, references) click to toggle source
# File lib/view_model/active_record/update_operation.rb, line 696
def insert_after(relative_to, references)
  insert_relative(relative_to, 1, references)
end
insert_before(relative_to, references) click to toggle source
# File lib/view_model/active_record/update_operation.rb, line 692
def insert_before(relative_to, references)
  insert_relative(relative_to, 0, references)
end
remove(vm_references) click to toggle source
# File lib/view_model/active_record/update_operation.rb, line 706
def remove(vm_references)
  removed_members = vm_references.map do |vm_ref|
    claim_existing_member(vm_ref)
  end
  remove_from_members(removed_members)
  orphaned_members.concat(removed_members)
end
replace(references) click to toggle source
# File lib/view_model/active_record/update_operation.rb, line 683
def replace(references)
  members.replace(claim_or_create_references(references))

  # Any unclaimed free members after building the update target are now
  # orphaned and their direct viewmodels can be released.
  orphaned_members.concat(free_members_by_indirect_ref.values)
  free_members_by_indirect_ref.clear
end
update(references) click to toggle source
# File lib/view_model/active_record/update_operation.rb, line 714
def update(references)
  claim_existing_references(references)
end

Private Instance Methods

claim_existing_member(indirect_vm_ref, ref_string = nil) click to toggle source

Claim an existing collection member for the update and optionally set its ref.

# File lib/view_model/active_record/update_operation.rb, line 763
def claim_existing_member(indirect_vm_ref, ref_string = nil)
  member = free_members_by_indirect_ref.delete(indirect_vm_ref) do
    raise ViewModel::DeserializationError::AssociatedNotFound.new(
      association_data.association_name.to_s, indirect_vm_ref, blame_reference)
  end
  member.ref_string = ref_string if ref_string
  member
end
claim_existing_references(references) click to toggle source

Reclaim existing members corresponding to the specified references or raise if not found.

# File lib/view_model/active_record/update_operation.rb, line 755
def claim_existing_references(references)
  references.each do |ref_string|
    indirect_vm_ref = update_context.resolve_reference(ref_string, blame_reference).viewmodel_reference
    claim_existing_member(indirect_vm_ref, ref_string)
  end
end
claim_or_create_member(indirect_vm_ref, ref_string) click to toggle source

Reclaim an existing member for an update and set its ref, or create a new one if not found.

# File lib/view_model/active_record/update_operation.rb, line 746
def claim_or_create_member(indirect_vm_ref, ref_string)
  member = free_members_by_indirect_ref.delete(indirect_vm_ref) do
    ReferencedCollectionMember.new(indirect_vm_ref, association_data.direct_viewmodel.for_new_model)
  end
  member.ref_string = ref_string
  member
end
claim_or_create_references(references) click to toggle source

Reclaim existing members corresponding to the specified references, or create new ones if not found.

# File lib/view_model/active_record/update_operation.rb, line 738
def claim_or_create_references(references)
  references.map do |ref_string|
    indirect_vm_ref = update_context.resolve_reference(ref_string, blame_reference).viewmodel_reference
    claim_or_create_member(indirect_vm_ref, ref_string)
  end
end
insert_relative(relative_vm_ref, offset, references) click to toggle source
# File lib/view_model/active_record/update_operation.rb, line 723
def insert_relative(relative_vm_ref, offset, references)
  new_members = claim_or_create_references(references)
  remove_from_members(new_members)

  index = members.find_index { |m| m.indirect_viewmodel_reference == relative_vm_ref }

  unless index
    raise ViewModel::DeserializationError::AssociatedNotFound.new(
      association_data.association_name.to_s, relative_vm_ref, blame_reference)
  end

  members.insert(index + offset, *new_members)
end
remove_from_members(removed_members) click to toggle source
# File lib/view_model/active_record/update_operation.rb, line 772
def remove_from_members(removed_members)
  s = removed_members.to_set
  members.reject! { |m| s.include?(m) }
end