Module: OceanDynamo::BelongsTo::ClassMethods

Defined in:
lib/ocean-dynamo/associations/belongs_to.rb

Overview


Class methods


Instance Method Summary collapse

Instance Method Details

#belongs_to(target, composite_key: false) ⇒ Object

Class macro to define the belongs_to relation. For example:

class Forum < OceanDynamo::Table dynamo_schema do attribute :name attribute :description end has_many :topics, dependent: :destroy end

class Topic < OceanDynamo::Table dynamo_schema(:guid) do attribute :title end belongs_to :forum has_many :posts, dependent: :destroy end

class Post < OceanDynamo::Table dynamo_schema(:guid) do attribute :body end belongs_to :topic, composite_key: true end

The only non-standard aspect of the above is composite_key: true, which is required as the Topic class itself has a belongs_to relation and thus has a composite key. This must be declared in the child class as it needs to know how to retrieve its parent. If you were to add a Comment class to the above with a has_many/belongs_to relation to Post, the Comment class would also have a belongs_to :post, composite_key: true statement, since Post already has a composite key due to its belongs_to relation to the Topic class.



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/ocean-dynamo/associations/belongs_to.rb', line 52

def belongs_to(target, composite_key: false)       # :master, "master", Master
  target_attr = target.to_s.underscore             # "master"
  target_attr_id = "#{target_attr}_id"             # "master_id"
  class_name = target_attr.classify                # "Master"
  define_class_if_not_defined(class_name)
  target_class = class_name.constantize            # Master

  assert_only_one_belongs_to!
  assert_range_key_not_specified!
  assert_hash_key_is_not_id!

  self.table_range_key = table_hash_key            # The RANGE KEY is variable
  self.table_hash_key = target_attr_id.to_sym      # The HASH KEY is the parent UUID

  attribute table_hash_key, :string                # Define :master_id
  define_attribute_accessors(table_hash_key)       # Define master_id, master_id=, master_id?

  # Make sure there always is a parent
  validates(table_hash_key, presence: true)        # Can't save without a parent_id

  # Define the range attribute (our unique UUID)
  attribute(table_range_key, :string, default: "") # Define :uuid
  define_attribute_accessors(table_range_key)      # define uuid, uuid=, uuid?


  # Define the parent id attribute 
  attribute target_attr_id, :reference, default: nil, target_class: target_class,
                            association: :belongs_to
  register_relation(target_class, :belongs_to)


  # Define accessors for instances
  self.class_eval "def #{target_attr}
                     @#{target_attr} ||= load_target_from_id('#{target_attr_id}', #{composite_key})
                   end"

  self.class_eval "def #{target_attr_id}
                     read_attribute('#{target_attr_id}')
                   end"

  self.class_eval "def #{target_attr}=(value) 
                     target, target_id = type_check_target(#{target_class}, value, #{composite_key})
                     write_attribute('#{target_attr_id}', target_id) 
                     @#{target_attr} = target
                     value
                   end"

  self.class_eval "def #{target_attr_id}=(value)
                     type_check_foreign_key('#{target_attr_id}', value)
                     write_attribute('#{target_attr_id}', value) 
                     @#{target_attr} = nil
                     value
                   end"

  # Define parent builders
  self.class_eval "def self.build_#{target_attr}(**opts)
                     #{target_class}.new(opts)
                   end"

  self.class_eval "def self.create_#{target_attr}(**opts)
                     #{target_class}.create(opts)
                   end"
end

#belongs_to_class ⇒ Object

Returns the class of the belongs_to association, or false if none.



129
130
131
# File 'lib/ocean-dynamo/associations/belongs_to.rb', line 129

def belongs_to_class
  has_belongs_to? && fields[table_hash_key]['target_class']
end

#has_belongs_to? ⇒ Boolean

Returns true if the class has a belongs_to association.

Returns:

  • (Boolean)


120
121
122
# File 'lib/ocean-dynamo/associations/belongs_to.rb', line 120

def has_belongs_to?
  fields[table_hash_key]['association'] == :belongs_to
end