Module: ActiveRecord::NestedAttributes

Defined in:
lib/composite_primary_keys/nested_attributes.rb

Instance Method Summary collapse

Instance Method Details

#assign_nested_attributes_for_collection_association(association_name, attributes_collection) ⇒ Object



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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
# File 'lib/composite_primary_keys/nested_attributes.rb', line 11

def assign_nested_attributes_for_collection_association(association_name, attributes_collection)
  options = self.nested_attributes_options[association_name]

  if attributes_collection.respond_to?(:permitted?)
    attributes_collection = attributes_collection.to_h
  end

  unless attributes_collection.is_a?(Hash) || attributes_collection.is_a?(Array)
    raise ArgumentError, "Hash or Array expected, got #{attributes_collection.class.name} (#{attributes_collection.inspect})"
  end

  check_record_limit!(options[:limit], attributes_collection)

  if attributes_collection.is_a? Hash
    keys = attributes_collection.keys
    attributes_collection = if keys.include?('id') || keys.include?(:id)
                              [attributes_collection]
                            else
                              attributes_collection.values
                            end
  end

  association = association(association_name)

  existing_records = if association.loaded?
                       association.target
                     # CPK
                     elsif association.reflection.klass.composite?
                       attributes_collection.map do |attribute_collection|
                         attribute_ids = attribute_collection['id'] || attribute_collection[:id]
                         if attribute_ids
                           ids = CompositePrimaryKeys::CompositeKeys.parse(attribute_ids)
                           eq_predicates = CompositePrimaryKeys::Predicates.cpk_id_predicate(association.klass.arel_table, association.klass.primary_key, ids)
                           association.scope.where(eq_predicates).to_a
                         else
                           []
                         end
                       end.flatten.compact
                     else
                       attribute_ids = attributes_collection.map {|a| a['id'] || a[:id] }.compact
                       attribute_ids.empty? ? [] : association.scope.where(association.klass.primary_key => attribute_ids)
                     end

  attributes_collection.each do |attributes|
    if attributes.respond_to?(:permitted?)
      attributes = attributes.to_h
    end
    attributes = attributes.with_indifferent_access

    if attributes["id"].blank?
      unless reject_new_record?(association_name, attributes)
        association.reader.build(attributes.except(*UNASSIGNABLE_KEYS))
      end
    elsif existing_record = cpk_detect_record(attributes['id'], existing_records)
      unless call_reject_if(association_name, attributes)
        # Make sure we are operating on the actual object which is in the association's
        # proxy_target array (either by finding it, or adding it if not found)
        # Take into account that the proxy_target may have changed due to callbacks
        target_record = cpk_detect_record(attributes['id'], association.target)
        if target_record
          existing_record = target_record
        else
          association.add_to_target(existing_record, skip_callbacks: true)
        end

        assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
      end
    else
      raise_nested_attributes_record_not_found!(association_name, attributes["id"])
    end
  end
end

#cpk_detect_record(id, records) ⇒ Object



3
4
5
6
7
8
9
# File 'lib/composite_primary_keys/nested_attributes.rb', line 3

def cpk_detect_record(id, records)
  id_string = id.is_a?(Array) ? CompositePrimaryKeys::CompositeKeys.new(id).to_s : id.to_s

  records.detect do |record|
    record.id.to_s == id_string
  end
end