acts_as_table 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.yardopts +1 -0
- data/LICENSE +30 -0
- data/README.md +256 -0
- data/Rakefile +13 -0
- data/app/models/acts_as_table/belongs_to.rb +81 -0
- data/app/models/acts_as_table/column_model.rb +89 -0
- data/app/models/acts_as_table/foreign_key.rb +299 -0
- data/app/models/acts_as_table/foreign_key_map.rb +121 -0
- data/app/models/acts_as_table/has_many.rb +90 -0
- data/app/models/acts_as_table/has_many_target.rb +40 -0
- data/app/models/acts_as_table/lense.rb +131 -0
- data/app/models/acts_as_table/primary_key.rb +108 -0
- data/app/models/acts_as_table/record.rb +109 -0
- data/app/models/acts_as_table/record_error.rb +50 -0
- data/app/models/acts_as_table/record_model.rb +194 -0
- data/app/models/acts_as_table/row_model.rb +285 -0
- data/app/models/acts_as_table/table.rb +41 -0
- data/app/models/acts_as_table/value.rb +80 -0
- data/app/models/concerns/acts_as_table/record_model_class_methods.rb +554 -0
- data/app/models/concerns/acts_as_table/value_provider.rb +223 -0
- data/app/models/concerns/acts_as_table/value_provider_association_methods.rb +57 -0
- data/config/locales/en.yml +8 -0
- data/db/migrate/1_acts_as_table_migration.rb +186 -0
- data/lib/acts_as_table.rb +288 -0
- data/lib/acts_as_table/adapter.rb +81 -0
- data/lib/acts_as_table/engine.rb +14 -0
- data/lib/acts_as_table/headers.rb +196 -0
- data/lib/acts_as_table/mapper.rb +464 -0
- data/lib/acts_as_table/path.rb +157 -0
- data/lib/acts_as_table/reader.rb +149 -0
- data/lib/acts_as_table/version.rb +4 -0
- data/lib/acts_as_table/writer.rb +116 -0
- metadata +181 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
module ActsAsTable
|
2
|
+
# ActsAsTable collection macro association target.
|
3
|
+
#
|
4
|
+
# @!attribute [rw] position
|
5
|
+
# Returns the position of this ActsAsTable collection macro association target.
|
6
|
+
#
|
7
|
+
# @return [Integer]
|
8
|
+
class HasManyTarget < ::ActiveRecord::Base
|
9
|
+
# @!parse
|
10
|
+
# include ActsAsTable::ValueProvider
|
11
|
+
# include ActsAsTable::ValueProviderAssociationMethods
|
12
|
+
|
13
|
+
self.table_name = ActsAsTable.has_many_targets_table
|
14
|
+
|
15
|
+
# Returns the ActsAsTable collection macro association for this target.
|
16
|
+
belongs_to :has_many, **{
|
17
|
+
class_name: 'ActsAsTable::HasMany',
|
18
|
+
inverse_of: :has_many_targets,
|
19
|
+
required: true,
|
20
|
+
}
|
21
|
+
|
22
|
+
# Returns the ActsAsTable record model for this ActsAsTable collection macro association target.
|
23
|
+
belongs_to :record_model, **{
|
24
|
+
class_name: 'ActsAsTable::RecordModel',
|
25
|
+
inverse_of: :has_many_targets,
|
26
|
+
required: true,
|
27
|
+
}
|
28
|
+
|
29
|
+
validates :position, **{
|
30
|
+
numericality: {
|
31
|
+
greater_than_or_equal_to: 1,
|
32
|
+
only_integer: true,
|
33
|
+
},
|
34
|
+
presence: true,
|
35
|
+
uniqueness: {
|
36
|
+
scope: ['has_many_id'],
|
37
|
+
},
|
38
|
+
}
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
module ActsAsTable
|
2
|
+
# ActsAsTable attribute accessor (value provider).
|
3
|
+
#
|
4
|
+
# @note The name "Lense" was selected for 2 reasons: similarity of behavior of this class and the corresponding type(s) in the Haskell package, [lens](https://hackage.haskell.org/package/lens); and that "Attribute" is not allowed as a Ruby on Rails model class name (because the corresponding table name would be "attributes", which would conflict with {ActiveRecord::AttributeMethods#attributes}).
|
5
|
+
#
|
6
|
+
# @!attribute [rw] default_value
|
7
|
+
# Returns the default value for this ActsAsTable attribute accessor.
|
8
|
+
#
|
9
|
+
# @return [String, nil]
|
10
|
+
# @!attribute [rw] method_name
|
11
|
+
# Returns the method name for this ActsAsTable attribute accessor (an `attr_reader` or a Ruby on Rails model column name).
|
12
|
+
#
|
13
|
+
# @return [String]
|
14
|
+
class Lense < ::ActiveRecord::Base
|
15
|
+
# @!parse
|
16
|
+
# include ActsAsTable::ValueProvider
|
17
|
+
# include ActsAsTable::ValueProvider::InstanceMethods
|
18
|
+
# include ActsAsTable::ValueProviderAssociationMethods
|
19
|
+
|
20
|
+
self.table_name = ActsAsTable.lenses_table
|
21
|
+
|
22
|
+
acts_as_table_value_provider
|
23
|
+
|
24
|
+
# Returns the ActsAsTable column model for this ActsAsTable attribute accessor or `nil`.
|
25
|
+
#
|
26
|
+
# @return [ActsAsTable::ColumnModel, nil]
|
27
|
+
belongs_to :column_model, **{
|
28
|
+
class_name: 'ActsAsTable::ColumnModel',
|
29
|
+
inverse_of: :lenses,
|
30
|
+
required: false,
|
31
|
+
}
|
32
|
+
|
33
|
+
# Returns the ActsAsTable record model for this ActsAsTable attribute accessor.
|
34
|
+
belongs_to :record_model, **{
|
35
|
+
class_name: 'ActsAsTable::RecordModel',
|
36
|
+
inverse_of: :lenses,
|
37
|
+
required: true,
|
38
|
+
}
|
39
|
+
|
40
|
+
# Returns the ActsAsTable values that have been provided by this ActsAsTable attribute accessor.
|
41
|
+
has_many :values, **{
|
42
|
+
as: :value_provider,
|
43
|
+
class_name: 'ActsAsTable::Value',
|
44
|
+
dependent: :restrict_with_exception,
|
45
|
+
foreign_key: 'value_provider_id',
|
46
|
+
foreign_type: 'value_provider_type',
|
47
|
+
inverse_of: :value_provider,
|
48
|
+
}
|
49
|
+
|
50
|
+
validates :default_value, **{
|
51
|
+
presence: {
|
52
|
+
unless: :column_model,
|
53
|
+
},
|
54
|
+
}
|
55
|
+
|
56
|
+
validates :method_name, **{
|
57
|
+
presence: true,
|
58
|
+
}
|
59
|
+
|
60
|
+
validate :record_model_class_must_respond_to_method_name, **{
|
61
|
+
if: ::Proc.new { |lense| lense.method_name.present? },
|
62
|
+
}
|
63
|
+
|
64
|
+
protected
|
65
|
+
|
66
|
+
# @param [ActiveRecord::Base, nil] base
|
67
|
+
# @return [Object, nil]
|
68
|
+
def _get_value(base = nil)
|
69
|
+
if base.nil?
|
70
|
+
nil
|
71
|
+
else
|
72
|
+
base.send(:"#{self.method_name}")
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# @param [ActiveRecord::Base, nil] base
|
77
|
+
# @param [Object, nil] new_value
|
78
|
+
# @return [Array<Object>]
|
79
|
+
def _set_value(base = nil, new_value = nil)
|
80
|
+
if base.nil?
|
81
|
+
[
|
82
|
+
nil,
|
83
|
+
false,
|
84
|
+
]
|
85
|
+
else
|
86
|
+
# @return [Object, nil]
|
87
|
+
orig_value = _get_value(base)
|
88
|
+
|
89
|
+
# @return [Boolean]
|
90
|
+
changed = !self.column_model.nil? && !(orig_value.nil? ? new_value.nil? : (new_value.nil? ? false : orig_value.to_s.eql?(new_value.to_s)))
|
91
|
+
|
92
|
+
[
|
93
|
+
base.send(:"#{self.method_name}=", new_value),
|
94
|
+
changed,
|
95
|
+
]
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
# @param [Class] klass
|
102
|
+
# @param [String] attribute_name
|
103
|
+
# @return [Boolean]
|
104
|
+
def _attr_accessor?(klass, attribute_name)
|
105
|
+
[
|
106
|
+
:"#{attribute_name}",
|
107
|
+
:"#{attribute_name}=",
|
108
|
+
].all? { |sym|
|
109
|
+
klass.instance_methods.include?(sym)
|
110
|
+
}
|
111
|
+
end
|
112
|
+
|
113
|
+
# @param [Class] klass
|
114
|
+
# @param [String] column_name
|
115
|
+
# @return [Boolean]
|
116
|
+
def _column?(klass, column_name)
|
117
|
+
klass.column_names.include?(column_name.to_s)
|
118
|
+
end
|
119
|
+
|
120
|
+
# @return [void]
|
121
|
+
def record_model_class_must_respond_to_method_name
|
122
|
+
self.record_model.try { |record_model| record_model.class_name.constantize rescue nil }.try { |klass|
|
123
|
+
unless _attr_accessor?(klass, self.method_name) || _column?(klass, self.method_name)
|
124
|
+
self.errors.add('method_name', :required)
|
125
|
+
end
|
126
|
+
}
|
127
|
+
|
128
|
+
return
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module ActsAsTable
|
2
|
+
# ActsAsTable primary key (value provider).
|
3
|
+
#
|
4
|
+
# @!attribute [rw] method_name
|
5
|
+
# Returns the method name for this ActsAsTable primary key (a Ruby on Rails model column name).
|
6
|
+
#
|
7
|
+
# @return [String]
|
8
|
+
class PrimaryKey < ::ActiveRecord::Base
|
9
|
+
# @!parse
|
10
|
+
# include ActsAsTable::ValueProvider
|
11
|
+
# include ActsAsTable::ValueProvider::InstanceMethods
|
12
|
+
# include ActsAsTable::ValueProviderAssociationMethods
|
13
|
+
|
14
|
+
self.table_name = ActsAsTable.primary_keys_table
|
15
|
+
|
16
|
+
acts_as_table_value_provider
|
17
|
+
|
18
|
+
# Returns the ActsAsTable column model for this ActsAsTable primary key or `nil`.
|
19
|
+
#
|
20
|
+
# @return [ActsAsTable::ColumnModel, nil]
|
21
|
+
belongs_to :column_model, **{
|
22
|
+
class_name: 'ActsAsTable::ColumnModel',
|
23
|
+
inverse_of: :primary_keys,
|
24
|
+
required: false,
|
25
|
+
}
|
26
|
+
|
27
|
+
# Returns the ActsAsTable record model for this ActsAsTable primary key.
|
28
|
+
belongs_to :record_model, **{
|
29
|
+
class_name: 'ActsAsTable::RecordModel',
|
30
|
+
inverse_of: :primary_keys,
|
31
|
+
required: true,
|
32
|
+
}
|
33
|
+
|
34
|
+
# Returns the ActsAsTable values that have been provided by this ActsAsTable primary key.
|
35
|
+
has_many :values, **{
|
36
|
+
as: :value_provider,
|
37
|
+
class_name: 'ActsAsTable::Value',
|
38
|
+
dependent: :restrict_with_exception,
|
39
|
+
foreign_key: 'value_provider_id',
|
40
|
+
foreign_type: 'value_provider_type',
|
41
|
+
inverse_of: :value_provider,
|
42
|
+
}
|
43
|
+
|
44
|
+
validates :method_name, **{
|
45
|
+
presence: true,
|
46
|
+
}
|
47
|
+
|
48
|
+
validates :record_model_id, **{
|
49
|
+
uniqueness: true,
|
50
|
+
}
|
51
|
+
|
52
|
+
validate :record_model_class_must_respond_to_method_name, **{
|
53
|
+
if: ::Proc.new { |primary_key| primary_key.method_name.present? },
|
54
|
+
}
|
55
|
+
|
56
|
+
protected
|
57
|
+
|
58
|
+
# @param [ActiveRecord::Base, nil] base
|
59
|
+
# @return [Object, nil]
|
60
|
+
def _get_value(base = nil)
|
61
|
+
if base.nil?
|
62
|
+
nil
|
63
|
+
else
|
64
|
+
base.send(:"#{self.method_name}")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# @param [ActiveRecord::Base, nil] base
|
69
|
+
# @param [Object, nil] new_value
|
70
|
+
# @return [Array<Object>]
|
71
|
+
def _set_value(base = nil, new_value = nil)
|
72
|
+
if base.nil?
|
73
|
+
[
|
74
|
+
nil,
|
75
|
+
false,
|
76
|
+
]
|
77
|
+
else
|
78
|
+
# @return [Object, nil]
|
79
|
+
orig_value = _get_value(base)
|
80
|
+
|
81
|
+
[
|
82
|
+
orig_value,
|
83
|
+
false,
|
84
|
+
]
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
# @param [Class] klass
|
91
|
+
# @param [String] column_name
|
92
|
+
# @return [Boolean]
|
93
|
+
def _column?(klass, column_name)
|
94
|
+
klass.column_names.include?(column_name.to_s)
|
95
|
+
end
|
96
|
+
|
97
|
+
# @return [void]
|
98
|
+
def record_model_class_must_respond_to_method_name
|
99
|
+
self.record_model.try { |record_model| record_model.class_name.constantize rescue nil }.try { |klass|
|
100
|
+
unless _column?(klass, self.method_name)
|
101
|
+
self.errors.add('method_name', :required)
|
102
|
+
end
|
103
|
+
}
|
104
|
+
|
105
|
+
return
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module ActsAsTable
|
2
|
+
# ActsAsTable record.
|
3
|
+
#
|
4
|
+
# @!attribute [rw] position
|
5
|
+
# Returns the position of this ActsAsTable record.
|
6
|
+
#
|
7
|
+
# @return [Integer]
|
8
|
+
# @!attribute [r] record_errors_count
|
9
|
+
# Returns the number of ActsAsTable record errors for this ActsAsTable record.
|
10
|
+
#
|
11
|
+
# @return [Integer]
|
12
|
+
# @!attribute [rw] record_model_changed
|
13
|
+
# Returns `true` if the ActsAsTable record model changed the record for this ActsAsTable record. Otherwise, returns `false`.
|
14
|
+
#
|
15
|
+
# @return [Boolean]
|
16
|
+
# @!attribute [r] values_count
|
17
|
+
# Returns the number of ActsAsTable values for this ActsAsTable record.
|
18
|
+
#
|
19
|
+
# @return [Integer]
|
20
|
+
class Record < ::ActiveRecord::Base
|
21
|
+
# @!parse
|
22
|
+
# include ActsAsTable::ValueProvider
|
23
|
+
# include ActsAsTable::ValueProviderAssociationMethods
|
24
|
+
|
25
|
+
self.table_name = ActsAsTable.records_table
|
26
|
+
|
27
|
+
# Returns the record for this ActsAsTable record or `nil`.
|
28
|
+
#
|
29
|
+
# @return [ActiveRecord::Base, nil]
|
30
|
+
belongs_to :base, **{
|
31
|
+
polymorphic: true,
|
32
|
+
required: false,
|
33
|
+
}
|
34
|
+
|
35
|
+
# Returns the ActsAsTable record model for this ActsAsTable record.
|
36
|
+
belongs_to :record_model, **{
|
37
|
+
class_name: 'ActsAsTable::RecordModel',
|
38
|
+
inverse_of: :records,
|
39
|
+
required: true,
|
40
|
+
}
|
41
|
+
|
42
|
+
# Returns the ActsAsTable table for this ActsAsTable record.
|
43
|
+
belongs_to :table, **{
|
44
|
+
class_name: 'ActsAsTable::Table',
|
45
|
+
counter_cache: 'records_count',
|
46
|
+
inverse_of: :records,
|
47
|
+
required: true,
|
48
|
+
}
|
49
|
+
|
50
|
+
# Returns the ActsAsTable record errors for this ActsAsTable record.
|
51
|
+
has_many :record_errors, -> { order(attribute_name: :asc, message: :asc) }, **{
|
52
|
+
autosave: true,
|
53
|
+
class_name: 'ActsAsTable::RecordError',
|
54
|
+
dependent: :destroy,
|
55
|
+
foreign_key: 'record_id',
|
56
|
+
inverse_of: :record,
|
57
|
+
validate: true,
|
58
|
+
}
|
59
|
+
|
60
|
+
# Returns the ActsAsTable values for this ActsAsTable record.
|
61
|
+
has_many :values, -> { order(position: :asc) }, **{
|
62
|
+
autosave: true,
|
63
|
+
class_name: 'ActsAsTable::Value',
|
64
|
+
dependent: :destroy,
|
65
|
+
foreign_key: 'record_id',
|
66
|
+
inverse_of: :record,
|
67
|
+
validate: true,
|
68
|
+
}
|
69
|
+
|
70
|
+
validates :position, **{
|
71
|
+
numericality: {
|
72
|
+
greater_than_or_equal_to: 1,
|
73
|
+
only_integer: true,
|
74
|
+
},
|
75
|
+
presence: true,
|
76
|
+
uniqueness: {
|
77
|
+
scope: ['table_id', 'record_model_id'],
|
78
|
+
},
|
79
|
+
}
|
80
|
+
|
81
|
+
# validates :record_model_changed, **{}
|
82
|
+
|
83
|
+
validate :record_must_be_valid_class, :record_model_must_belong_to_row_model_for_table, **{
|
84
|
+
if: ::Proc.new { |record| record.record_model.present? },
|
85
|
+
}
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
# @return [void]
|
90
|
+
def record_must_be_valid_class
|
91
|
+
self.record_type.try { |record_type|
|
92
|
+
unless record_type.eql?(self.record_model.class_name)
|
93
|
+
self.errors.add('record_type', :invalid)
|
94
|
+
end
|
95
|
+
}
|
96
|
+
end
|
97
|
+
|
98
|
+
# @return [void]
|
99
|
+
def record_model_must_belong_to_row_model_for_table
|
100
|
+
self.table.try(:row_model).try(:record_models).try { |record_models|
|
101
|
+
unless record_models.include?(self.record_model)
|
102
|
+
self.errors.add('record_model_id', :invalid)
|
103
|
+
end
|
104
|
+
}
|
105
|
+
|
106
|
+
return
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module ActsAsTable
|
2
|
+
# ActsAsTable record error.
|
3
|
+
#
|
4
|
+
# @!attribute [rw] attribute_name
|
5
|
+
# Returns the attribute name for this ActsAsTable record error.
|
6
|
+
#
|
7
|
+
# @note The attribute name for model-level errors is "base".
|
8
|
+
#
|
9
|
+
# @return [String]
|
10
|
+
# @!attribute [rw] message
|
11
|
+
# Returns the message for this ActsAsTable record error.
|
12
|
+
#
|
13
|
+
# @return [String]
|
14
|
+
class RecordError < ::ActiveRecord::Base
|
15
|
+
# @!parse
|
16
|
+
# include ActsAsTable::ValueProvider
|
17
|
+
# include ActsAsTable::ValueProviderAssociationMethods
|
18
|
+
|
19
|
+
self.table_name = ActsAsTable.record_errors_table
|
20
|
+
|
21
|
+
# Returns the ActsAsTable record for this error.
|
22
|
+
belongs_to :record, **{
|
23
|
+
class_name: 'ActsAsTable::Record',
|
24
|
+
counter_cache: 'record_errors_count',
|
25
|
+
inverse_of: :record_errors,
|
26
|
+
required: true,
|
27
|
+
}
|
28
|
+
|
29
|
+
# Returns the ActsAsTable value for this error or `nil`.
|
30
|
+
#
|
31
|
+
# @return [ActsAsTable::Value, nil]
|
32
|
+
belongs_to :value, **{
|
33
|
+
class_name: 'ActsAsTable::Value',
|
34
|
+
counter_cache: 'record_errors_count',
|
35
|
+
inverse_of: :record_errors,
|
36
|
+
required: false,
|
37
|
+
}
|
38
|
+
|
39
|
+
validates :attribute_name, **{
|
40
|
+
presence: true,
|
41
|
+
}
|
42
|
+
|
43
|
+
validates :message, **{
|
44
|
+
presence: true,
|
45
|
+
uniqueness: {
|
46
|
+
scope: ['record_id', 'attribute_name'],
|
47
|
+
},
|
48
|
+
}
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,194 @@
|
|
1
|
+
module ActsAsTable
|
2
|
+
# ActsAsTable record model (value provider).
|
3
|
+
#
|
4
|
+
# @!attribute [rw] class_name
|
5
|
+
# Returns the ActiveRecord model class name for this ActsAsTable record model.
|
6
|
+
#
|
7
|
+
# @return [String]
|
8
|
+
class RecordModel < ::ActiveRecord::Base
|
9
|
+
# @!parse
|
10
|
+
# include ActsAsTable::ValueProvider
|
11
|
+
# include ActsAsTable::ValueProvider::InstanceMethods
|
12
|
+
# include ActsAsTable::ValueProviderAssociationMethods
|
13
|
+
|
14
|
+
self.table_name = ActsAsTable.record_models_table
|
15
|
+
|
16
|
+
acts_as_table_value_provider
|
17
|
+
|
18
|
+
# Returns the ActsAsTable row model for this ActsAsTable record model.
|
19
|
+
belongs_to :row_model, **{
|
20
|
+
class_name: 'ActsAsTable::RowModel',
|
21
|
+
inverse_of: :record_models,
|
22
|
+
required: true,
|
23
|
+
}
|
24
|
+
|
25
|
+
# Returns the ActsAsTable singular macro associations where this ActsAsTable record model is the source of the association.
|
26
|
+
has_many :belongs_tos_as_source, **{
|
27
|
+
autosave: true,
|
28
|
+
class_name: 'ActsAsTable::BelongsTo',
|
29
|
+
dependent: :destroy,
|
30
|
+
foreign_key: 'source_record_model_id',
|
31
|
+
inverse_of: :source_record_model,
|
32
|
+
validate: true,
|
33
|
+
}
|
34
|
+
|
35
|
+
# Returns the ActsAsTable singular macro associations where this ActsAsTable record model is the target of the association.
|
36
|
+
has_many :belongs_tos_as_target, **{
|
37
|
+
autosave: true,
|
38
|
+
class_name: 'ActsAsTable::BelongsTo',
|
39
|
+
dependent: :destroy,
|
40
|
+
foreign_key: 'target_record_model_id',
|
41
|
+
inverse_of: :target_record_model,
|
42
|
+
validate: true,
|
43
|
+
}
|
44
|
+
|
45
|
+
# Returns the ActsAsTable foreign keys for this ActsAsTable record model.
|
46
|
+
has_many :foreign_keys, **{
|
47
|
+
autosave: true,
|
48
|
+
class_name: 'ActsAsTable::ForeignKey',
|
49
|
+
dependent: :destroy,
|
50
|
+
foreign_key: 'record_model_id',
|
51
|
+
inverse_of: :record_model,
|
52
|
+
validate: true,
|
53
|
+
}
|
54
|
+
|
55
|
+
# Returns the ActsAsTable collection macro associations where this ActsAsTable record model is the source of the association.
|
56
|
+
has_many :has_manies_as_source, **{
|
57
|
+
autosave: true,
|
58
|
+
class_name: 'ActsAsTable::HasMany',
|
59
|
+
dependent: :destroy,
|
60
|
+
foreign_key: 'source_record_model_id',
|
61
|
+
inverse_of: :source_record_model,
|
62
|
+
validate: true,
|
63
|
+
}
|
64
|
+
|
65
|
+
# Returns the ActsAsTable collection macro associations where this ActsAsTable record model is the target of the association.
|
66
|
+
has_many :has_manies_as_target, -> { readonly }, **{
|
67
|
+
source: :has_many,
|
68
|
+
through: :has_many_targets,
|
69
|
+
}
|
70
|
+
|
71
|
+
# Returns the ActsAsTable collection macro association targets for this ActsAsTable record model.
|
72
|
+
has_many :has_many_targets, **{
|
73
|
+
autosave: true,
|
74
|
+
class_name: 'ActsAsTable::HasManyTarget',
|
75
|
+
dependent: :destroy,
|
76
|
+
foreign_key: 'record_model_id',
|
77
|
+
inverse_of: :record_model,
|
78
|
+
validate: true,
|
79
|
+
}
|
80
|
+
|
81
|
+
# Returns the ActsAsTable attribute accessors for this ActsAsTable record model.
|
82
|
+
has_many :lenses, **{
|
83
|
+
autosave: true,
|
84
|
+
class_name: 'ActsAsTable::Lense',
|
85
|
+
dependent: :destroy,
|
86
|
+
foreign_key: 'record_model_id',
|
87
|
+
inverse_of: :record_model,
|
88
|
+
validate: true,
|
89
|
+
}
|
90
|
+
|
91
|
+
# Returns the ActsAsTable primary keys for this ActsAsTable record model.
|
92
|
+
has_many :primary_keys, **{
|
93
|
+
autosave: true,
|
94
|
+
class_name: 'ActsAsTable::PrimaryKey',
|
95
|
+
dependent: :destroy,
|
96
|
+
foreign_key: 'record_model_id',
|
97
|
+
inverse_of: :record_model,
|
98
|
+
validate: true,
|
99
|
+
}
|
100
|
+
|
101
|
+
# Returns the ActsAsTable records that have been provided by this ActsAsTable record model.
|
102
|
+
has_many :records, **{
|
103
|
+
class_name: 'ActsAsTable::Record',
|
104
|
+
dependent: :restrict_with_exception,
|
105
|
+
foreign_key: 'record_model_id',
|
106
|
+
inverse_of: :record_model,
|
107
|
+
}
|
108
|
+
|
109
|
+
# Returns the ActsAsTable row models where this ActsAsTable record model is the root.
|
110
|
+
has_many :row_models_as_root, **{
|
111
|
+
class_name: 'ActsAsTable::RowModel',
|
112
|
+
dependent: :restrict_with_exception,
|
113
|
+
foreign_key: 'root_record_model_id',
|
114
|
+
inverse_of: :root_record_model,
|
115
|
+
}
|
116
|
+
|
117
|
+
validates :class_name, **{
|
118
|
+
presence: true,
|
119
|
+
}
|
120
|
+
|
121
|
+
validate :base_must_be_reachable
|
122
|
+
|
123
|
+
validate :class_name_must_constantize, **{
|
124
|
+
if: ::Proc.new { |record_model| record_model.class_name.present? },
|
125
|
+
}
|
126
|
+
|
127
|
+
# Get the value for the given record using the given options.
|
128
|
+
#
|
129
|
+
# @param [ActiveRecord::Base, nil] base
|
130
|
+
# @param [Hash<Symbol, Object>] options
|
131
|
+
# @option options [Boolean] :default
|
132
|
+
# @return [ActsAsTable::ValueProvider::WrappedValue]
|
133
|
+
def get_value(base = nil, **options)
|
134
|
+
unless base.nil? || self.class_name.eql?(base.class.name)
|
135
|
+
raise ::ArgumentError.new("record - invalid class - expected: #{self.class_name.inspect}, found: #{base.inspect}")
|
136
|
+
end
|
137
|
+
|
138
|
+
# @return [Hash<ActsAsTable::ValueProvider::InstanceMethods, Object>]
|
139
|
+
value_by_value_provider = self.each_acts_as_table_value_provider(except: [:row_model]).inject({}) { |acc, value_provider|
|
140
|
+
acc[value_provider] ||= base.nil? ? ActsAsTable.adapter.wrap_value_for(value_provider, base, nil, nil) : ActsAsTable.adapter.get_value_for(value_provider, base, **options)
|
141
|
+
acc
|
142
|
+
}
|
143
|
+
|
144
|
+
ActsAsTable.adapter.wrap_value_for(self, base, nil, value_by_value_provider)
|
145
|
+
end
|
146
|
+
|
147
|
+
# Set the new value for the given record using the given options.
|
148
|
+
#
|
149
|
+
# @param [ActiveRecord::Base, nil] base
|
150
|
+
# @param [Hash<ActsAsTable::ValueProvider::InstanceMethods, Object>] new_value_by_value_provider
|
151
|
+
# @param [Hash<Symbol, Object>] options
|
152
|
+
# @option options [Boolean] :default
|
153
|
+
# @return [ActsAsTable::ValueProvider::WrappedValue]
|
154
|
+
def set_value(base = nil, new_value_by_value_provider = {}, **options)
|
155
|
+
unless base.nil? || self.class_name.eql?(base.class.name)
|
156
|
+
raise ::ArgumentError.new("record - invalid class - expected: #{self.class_name.inspect}, found: #{base.inspect}")
|
157
|
+
end
|
158
|
+
|
159
|
+
# @return [Array<Object>]
|
160
|
+
value_by_value_provider, changed = *self.each_acts_as_table_value_provider(except: [:row_model]).inject([{}, false]) { |acc, value_provider|
|
161
|
+
# @return [Object, nil]
|
162
|
+
new_value = new_value_by_value_provider.try(:[], value_provider)
|
163
|
+
|
164
|
+
acc[0][value_provider] ||= base.nil? ? ActsAsTable.adapter.wrap_value_for(value_provider, base, nil, nil) : ActsAsTable.adapter.set_value_for(value_provider, base, new_value, **options)
|
165
|
+
acc[1] ||= acc[0][value_provider].changed?
|
166
|
+
acc
|
167
|
+
}
|
168
|
+
|
169
|
+
ActsAsTable.adapter.wrap_value_for(self, base, nil, value_by_value_provider, changed: changed)
|
170
|
+
end
|
171
|
+
|
172
|
+
private
|
173
|
+
|
174
|
+
# @return [void]
|
175
|
+
def base_must_be_reachable
|
176
|
+
if self.row_model.try(:reachable_record_model?, self) == false
|
177
|
+
self.errors.add(:base, :unreachable)
|
178
|
+
end
|
179
|
+
|
180
|
+
return
|
181
|
+
end
|
182
|
+
|
183
|
+
# @return [void]
|
184
|
+
def class_name_must_constantize
|
185
|
+
begin
|
186
|
+
self.class_name.constantize
|
187
|
+
rescue ::NameError
|
188
|
+
self.errors.add('class_name', :invalid)
|
189
|
+
end
|
190
|
+
|
191
|
+
return
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|