Class: HasHelpers::BaseConstructor

Inherits:
SimpleDelegator
  • Object
show all
Defined in:
app/constructors/has_helpers/base_constructor.rb

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Class Attribute Details

.has_many_ids_associationsObject (readonly)

Returns the value of attribute has_many_ids_associations.



9
10
11
# File 'app/constructors/has_helpers/base_constructor.rb', line 9

def has_many_ids_associations
  @has_many_ids_associations
end

Class Method Details

.has_many_ids(*associations) ⇒ Object

Sets up the constructor to handle [association_ids] attributes, without immediately executing the database statements, which is the Rails default.

Example

Class Report::Constructor < :HasHelpersBaseConstructor

class Report has an association: has_many :users, through: :shares

has_many_ids :users end

The example above will allow report[user_ids] attribute to be set and build the associated objects in memory. In this case, if report[user_ids] = [1], it will execute report.shares.build(user_id: 1) Any existing objects with the ids not included in this parameter will be marked for destruction.



25
26
27
28
# File 'app/constructors/has_helpers/base_constructor.rb', line 25

def has_many_ids(*associations)
  @has_many_ids_associations ||= []
  @has_many_ids_associations.concat associations
end

Instance Method Details

#assign_attributes(object_attrs) ⇒ Object



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
# File 'app/constructors/has_helpers/base_constructor.rb', line 31

def assign_attributes(object_attrs)
  attrs = object_attrs.dup

  # Build/destroy has_many objects from "object_ids" params
  self.class.has_many_ids_associations.each do |association_name|
    association = object.class.reflect_on_association(association_name)
    association_key = association.foreign_key.to_s.pluralize
    association_to_build = association.through_reflection

    if attrs[association_key]
      association_primary_key = association.association_primary_key.to_s
      type_caster = association.klass.type_caster

      # Get ids from parameters, casting them to their correct type for the database.
      object_ids = attrs.delete(association_key).select(&:present?).map { |val| type_caster.type_cast_for_database(association_primary_key, val) }
      persisted_object_ids = object.send(association.name).map(&:id)

      # Mark for destruction any object that's not included in the attributes.
      object.send(association_to_build.name).reject do |assc_object|
        # skip any object that doesn't have this foreign key set.
        assc_object.send(association.foreign_key).blank? || object_ids.include?(assc_object.send(association.foreign_key))
      end.each(&:mark_for_destruction)
      (object_ids - persisted_object_ids).each do |new_object_id|
        object.send(association_to_build.name).build(association.foreign_key => new_object_id)
      end
    end
  end

  object.assign_attributes(attrs)
end