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_classObject

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