module OceanDynamo::HasMany::ClassMethods


Class methods

Public Instance Methods

has_many(children, dependent: :delete) click to toggle source

Defines a has_many relation to a belongs_to class.

The dependent: keyword arg may be :destroy, :delete or :nullify and have the same semantics as in ActiveRecord.

Using :nullify is a Bad Idea on DynamoDB, as it has to first read, then delete, and finally recreate each record. You should redesign your application to user either :delete (the default) or :destroy instead.

# File lib/ocean-dynamo/associations/has_many.rb, line 28
def has_many(children, dependent: :delete)             # :children
  children_attr = children.to_s.underscore             # "children"
  class_name = children_attr.classify                  # "Child"
  define_class_if_not_defined(class_name)
  child_class = class_name.constantize                 # Child
  register_relation(child_class, :has_many)

  # Handle children= after create and update
  after_save do |p|
    new_children = instance_variable_get("@#{children_attr}")  
    if new_children  # TODO: only do this for dirty collections
      write_children child_class, new_children
      map_children child_class do |c|
        next if new_children.include?(c)
        c.destroy
      end
    end 
    true
  end

  if dependent == :destroy
    before_destroy do |p|
      map_children(child_class, &:destroy)
      p.instance_variable_set "@#{children_attr}", nil
      true
    end

  elsif dependent == :delete
    before_destroy do |p|
      delete_children(child_class)
      p.instance_variable_set "@#{children_attr}", nil
   end

  elsif dependent == :nullify
    before_destroy do |p|
      nullify_children(child_class)
      p.instance_variable_set "@#{children_attr}", nil
      true
    end

  else
    raise ArgumentError, ":dependent must be :destroy, :delete, or :nullify"
  end

  # Define accessors for instances
  attr_accessor children_attr
  self.class_eval "def #{children_attr}(force_reload=false) 
                     @#{children_attr} = false if force_reload
                     @#{children_attr} ||= read_children(#{child_class})
                   end"
  self.class_eval "def #{children_attr}=(value)
                     @#{children_attr} = value
                   end"
  self.class_eval "def #{children_attr}? 
                     @#{children_attr} ||= read_children(#{child_class})
                     @#{children_attr}.present?
                   end"
end