Class: ActsAsTable::HasMany

Inherits:
ActiveRecord::Base
  • Object
show all
Defined in:
app/models/acts_as_table/has_many.rb

Overview

ActsAsTable collection macro association.

Instance Attribute Summary collapse

Belongs to collapse

Has many collapse

Instance Attribute Details

#macroString

Note:

The macro must be either :has_many or :has_and_belongs_to_many.

Returns the symbolic name for the macro for this ActsAsTable collection macro association.

Returns:

  • (String)


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
83
84
85
86
87
88
89
# File 'app/models/acts_as_table/has_many.rb', line 14

class HasMany < ::ActiveRecord::Base
  # @!parse
  #   include ActsAsTable::ValueProvider
  #   include ActsAsTable::ValueProviderAssociationMethods

  self.table_name = ActsAsTable.has_manies_table

  # Returns the ActsAsTable row model for this ActsAsTable collection macro association.
  belongs_to :row_model, **{
    class_name: 'ActsAsTable::RowModel',
    inverse_of: :has_manies,
    required: true,
  }

  # Returns the source ActsAsTable record model for this ActsAsTable collection macro association.
  belongs_to :source_record_model, **{
    class_name: 'ActsAsTable::RecordModel',
    inverse_of: :has_manies_as_source,
    required: true,
  }

  # Returns the targets for this ActsAsTable collection macro association.
  has_many :has_many_targets, -> { order(position: :asc) }, **{
    autosave: true,
    class_name: 'ActsAsTable::HasManyTarget',
    dependent: :destroy,
    foreign_key: 'has_many_id',
    inverse_of: :has_many,
    validate: true,
  }

  accepts_nested_attributes_for :has_many_targets, **{
    allow_destroy: true,
  }

  validates :macro, **{
    inclusion: {
      in: ['has_many', 'has_and_belongs_to_many'],
    },
    presence: true,
  }

  validates :method_name, **{
    presence: true,
  }

  validate :macro_and_method_name_must_be_valid_association, **{
    if: ::Proc.new { |has_many| has_many.macro.present? && has_many.method_name.present? },
  }

  private

  # @return [void]
  def macro_and_method_name_must_be_valid_association
    self.source_record_model.try { |record_model| record_model.class_name.constantize rescue nil }.try { |source_klass|
      # @return [ActiveRecord::Reflection::MacroReflection]
      reflection = source_klass.reflect_on_association(self.method_name)

      if reflection.nil?
        self.errors.add('method_name', :required)
      elsif self.macro.eql?(reflection.macro.to_s)
        self.has_many_targets.each do |has_many_target|
          has_many_target.record_model.try { |record_model| record_model.class_name.constantize rescue nil }.try { |target_klass|
            unless reflection.klass == target_klass
              has_many_target.errors.add('record_model_id', :invalid)
            end
          }
        end
      else
        self.errors.add('method_name', :invalid)
      end
    }

    return
  end
end

#method_nameString

Returns the method name for this ActsAsTable collection macro association.

Returns:

  • (String)


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
83
84
85
86
87
88
89
# File 'app/models/acts_as_table/has_many.rb', line 14

class HasMany < ::ActiveRecord::Base
  # @!parse
  #   include ActsAsTable::ValueProvider
  #   include ActsAsTable::ValueProviderAssociationMethods

  self.table_name = ActsAsTable.has_manies_table

  # Returns the ActsAsTable row model for this ActsAsTable collection macro association.
  belongs_to :row_model, **{
    class_name: 'ActsAsTable::RowModel',
    inverse_of: :has_manies,
    required: true,
  }

  # Returns the source ActsAsTable record model for this ActsAsTable collection macro association.
  belongs_to :source_record_model, **{
    class_name: 'ActsAsTable::RecordModel',
    inverse_of: :has_manies_as_source,
    required: true,
  }

  # Returns the targets for this ActsAsTable collection macro association.
  has_many :has_many_targets, -> { order(position: :asc) }, **{
    autosave: true,
    class_name: 'ActsAsTable::HasManyTarget',
    dependent: :destroy,
    foreign_key: 'has_many_id',
    inverse_of: :has_many,
    validate: true,
  }

  accepts_nested_attributes_for :has_many_targets, **{
    allow_destroy: true,
  }

  validates :macro, **{
    inclusion: {
      in: ['has_many', 'has_and_belongs_to_many'],
    },
    presence: true,
  }

  validates :method_name, **{
    presence: true,
  }

  validate :macro_and_method_name_must_be_valid_association, **{
    if: ::Proc.new { |has_many| has_many.macro.present? && has_many.method_name.present? },
  }

  private

  # @return [void]
  def macro_and_method_name_must_be_valid_association
    self.source_record_model.try { |record_model| record_model.class_name.constantize rescue nil }.try { |source_klass|
      # @return [ActiveRecord::Reflection::MacroReflection]
      reflection = source_klass.reflect_on_association(self.method_name)

      if reflection.nil?
        self.errors.add('method_name', :required)
      elsif self.macro.eql?(reflection.macro.to_s)
        self.has_many_targets.each do |has_many_target|
          has_many_target.record_model.try { |record_model| record_model.class_name.constantize rescue nil }.try { |target_klass|
            unless reflection.klass == target_klass
              has_many_target.errors.add('record_model_id', :invalid)
            end
          }
        end
      else
        self.errors.add('method_name', :invalid)
      end
    }

    return
  end
end

Instance Method Details

#has_many_targetsActiveRecord::Relation<ActsAsTable::HasManyTarget>

Returns the targets for this ActsAsTable collection macro association.

Returns:

See Also:



36
37
38
39
40
41
42
43
# File 'app/models/acts_as_table/has_many.rb', line 36

has_many :has_many_targets, -> { order(position: :asc) }, **{
  autosave: true,
  class_name: 'ActsAsTable::HasManyTarget',
  dependent: :destroy,
  foreign_key: 'has_many_id',
  inverse_of: :has_many,
  validate: true,
}

#row_modelActsAsTable::RowModel

Returns the ActsAsTable row model for this ActsAsTable collection macro association.



22
23
24
25
26
# File 'app/models/acts_as_table/has_many.rb', line 22

belongs_to :row_model, **{
  class_name: 'ActsAsTable::RowModel',
  inverse_of: :has_manies,
  required: true,
}

#source_record_modelActsAsTable::RecordModel

Returns the source ActsAsTable record model for this ActsAsTable collection macro association.



29
30
31
32
33
# File 'app/models/acts_as_table/has_many.rb', line 29

belongs_to :source_record_model, **{
  class_name: 'ActsAsTable::RecordModel',
  inverse_of: :has_manies_as_source,
  required: true,
}