Module: ActiveRecord::JSONB::Associations::HasManyAssociation

Defined in:
lib/activerecord/jsonb/associations/has_many_association.rb

Overview

:nodoc:

Instance Method Summary collapse

Instance Method Details

#create_scopeObject

rubocop:disable Metrics/AbcSize



57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/activerecord/jsonb/associations/has_many_association.rb', line 57

def create_scope
  super.tap do |scope|
    next unless options.key?(:store)

    key = reflection.foreign_key.pluralize
    scope[options[:store].to_s] ||= {}
    scope[options[:store].to_s][key] ||= []
    scope[options[:store].to_s][key] << owner[
      reflection.active_record_primary_key
    ]
  end
end

#creation_attributesObject

rubocop:disable Metrics/AbcSize



42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/activerecord/jsonb/associations/has_many_association.rb', line 42

def creation_attributes
  return super unless reflection.options.key?(:store)

  attributes = {}
  jsonb_store = reflection.options[:store]
  attributes[jsonb_store] ||= {}
  attributes[jsonb_store][reflection.foreign_key.pluralize] = []
  attributes[jsonb_store][reflection.foreign_key.pluralize] <<
    owner[reflection.active_record_primary_key]

  attributes
end

#delete_count(method, scope) ⇒ Object

rubocop:disable Metrics/AbcSize



97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/activerecord/jsonb/associations/has_many_association.rb', line 97

def delete_count(method, scope)
  store = reflection.options[:foreign_store] ||
          reflection.options[:store]
  return super if method == :delete_all || !store

  if reflection.options.key?(:foreign_store)
    remove_jsonb_foreign_id_on_belongs_to(store, reflection.foreign_key)
  else
    remove_jsonb_foreign_id_on_habtm(
      store, reflection.foreign_key.pluralize, owner.id
    )
  end
end

#delete_records(records, method) ⇒ Object

rubocop:enable Metrics/MethodLength, Metrics/AbcSize



91
92
93
94
# File 'lib/activerecord/jsonb/associations/has_many_association.rb', line 91

def delete_records(records, method)
  return super unless options.key?(:store)
  super(records, :delete)
end

#ids_readerObject



5
6
7
8
9
10
11
12
13
# File 'lib/activerecord/jsonb/associations/has_many_association.rb', line 5

def ids_reader
  return super unless reflection.options.key?(:store)

  Array(
    owner[reflection.options[:store]][
      "#{reflection.name.to_s.singularize}_ids"
    ]
  )
end

#insert_record(record, validate = true, raise = false) ⇒ Object

rubocop:disable Metrics/MethodLength, Metrics/AbcSize



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/activerecord/jsonb/associations/has_many_association.rb', line 72

def insert_record(record, validate = true, raise = false)
  super.tap do |super_result|
    next unless options.key?(:store)
    next unless super_result

    key = "#{record.model_name.singular}_ids"
    jsonb_column = options[:store]

    owner.class.where(
      owner.class.primary_key => owner[owner.class.primary_key]
    ).update_all(%(
      #{jsonb_column} = jsonb_set(#{jsonb_column}, '{#{key}}',
      coalesce(#{jsonb_column}->'#{key}', '[]'::jsonb) ||
      '[#{record[klass.primary_key]}]'::jsonb)
    ))
  end
end

#remove_jsonb_foreign_id_on_belongs_to(store, foreign_key) ⇒ Object

rubocop:enable Metrics/AbcSize



112
113
114
# File 'lib/activerecord/jsonb/associations/has_many_association.rb', line 112

def remove_jsonb_foreign_id_on_belongs_to(store, foreign_key)
  scope.update_all("#{store} = #{store} #- '{#{foreign_key}}'")
end

#remove_jsonb_foreign_id_on_habtm(store, foreign_key, owner_id) ⇒ Object



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/activerecord/jsonb/associations/has_many_association.rb', line 116

def remove_jsonb_foreign_id_on_habtm(store, foreign_key, owner_id)
  # PostgreSQL can only delete jsonb array elements by text or index.
  # Therefore we have to convert the jsonb array to PostgreSQl array,
  # remove the element, and convert it back
  scope.update_all(
    %(
      #{store} = jsonb_set(#{store}, '{#{foreign_key}}',
        to_jsonb(
          array_remove(
            array(select * from jsonb_array_elements(
              (#{store}->'#{foreign_key}'))),
            '#{owner_id}')))
    )
  )
end

#set_owner_attributes(record) ⇒ Object

rubocop:disable Naming/AccessorMethodName



16
17
18
19
20
21
22
23
24
25
26
# File 'lib/activerecord/jsonb/associations/has_many_association.rb', line 16

def set_owner_attributes(record)
  return super unless reflection.options.key?(:store)

  creation_attributes.each do |key, value|
    if key == reflection.options[:store]
      set_store_attributes(record, key, value)
    else
      record[key] = value
    end
  end
end

#set_store_attributes(record, store_column, attributes) ⇒ Object

rubocop:enable Naming/AccessorMethodName



29
30
31
32
33
34
35
36
37
38
39
# File 'lib/activerecord/jsonb/associations/has_many_association.rb', line 29

def set_store_attributes(record, store_column, attributes)
  attributes.each do |key, value|
    if value.is_a?(Array)
      record[store_column][key] ||= []
      record[store_column][key] =
        record[store_column][key].concat(value).uniq
    else
      record[store_column] = value
    end
  end
end