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,299 @@
|
|
1
|
+
module ActsAsTable
|
2
|
+
# ActsAsTable foreign key (value provider).
|
3
|
+
#
|
4
|
+
# @!attribute [rw] default_value
|
5
|
+
# Returns the default value for this ActsAsTable foreign key.
|
6
|
+
#
|
7
|
+
# @return [String, nil]
|
8
|
+
# @!attribute [rw] method_name
|
9
|
+
# Returns the method name for this ActsAsTable foreign key (a `:belongs_to` association).
|
10
|
+
#
|
11
|
+
# @return [String]
|
12
|
+
# @!attribute [rw] polymorphic
|
13
|
+
# Returns 'true' if this ActsAsTable foreign key is polymorphic. Otherwise, returns `false`. By default, this is `false`.
|
14
|
+
#
|
15
|
+
# @return [Boolean]
|
16
|
+
# @!attribute [rw] primary_key
|
17
|
+
# Returns the name of the method that returns the primary key used for the association. By default, this is `id`.
|
18
|
+
#
|
19
|
+
# @return [String]
|
20
|
+
class ForeignKey < ::ActiveRecord::Base
|
21
|
+
# @!parse
|
22
|
+
# include ActsAsTable::ValueProvider
|
23
|
+
# include ActsAsTable::ValueProvider::InstanceMethods
|
24
|
+
# include ActsAsTable::ValueProviderAssociationMethods
|
25
|
+
|
26
|
+
self.table_name = ActsAsTable.foreign_keys_table
|
27
|
+
|
28
|
+
acts_as_table_value_provider
|
29
|
+
|
30
|
+
# Returns the ActsAsTable column model for this ActsAsTable foreign key or `nil`.
|
31
|
+
#
|
32
|
+
# @return [ActsAsTable::ColumnModel, nil]
|
33
|
+
belongs_to :column_model, **{
|
34
|
+
class_name: 'ActsAsTable::ColumnModel',
|
35
|
+
inverse_of: :foreign_keys,
|
36
|
+
required: false,
|
37
|
+
}
|
38
|
+
|
39
|
+
# Returns the ActsAsTable record model for this ActsAsTable foreign key.
|
40
|
+
belongs_to :record_model, **{
|
41
|
+
class_name: 'ActsAsTable::RecordModel',
|
42
|
+
inverse_of: :foreign_keys,
|
43
|
+
required: true,
|
44
|
+
}
|
45
|
+
|
46
|
+
# Returns the maps for this ActsAsTable foreign key.
|
47
|
+
has_many :foreign_key_maps, -> { order(position: :asc) }, **{
|
48
|
+
autosave: true,
|
49
|
+
class_name: 'ActsAsTable::ForeignKeyMap',
|
50
|
+
dependent: :destroy,
|
51
|
+
foreign_key: 'foreign_key_id',
|
52
|
+
inverse_of: :foreign_key,
|
53
|
+
validate: true,
|
54
|
+
}
|
55
|
+
|
56
|
+
# Returns the ActsAsTable values that have been provided by this ActsAsTable foreign key.
|
57
|
+
has_many :values, **{
|
58
|
+
as: :value_provider,
|
59
|
+
class_name: 'ActsAsTable::Value',
|
60
|
+
dependent: :restrict_with_exception,
|
61
|
+
foreign_key: 'value_provider_id',
|
62
|
+
foreign_type: 'value_provider_type',
|
63
|
+
inverse_of: :value_provider,
|
64
|
+
}
|
65
|
+
|
66
|
+
accepts_nested_attributes_for :foreign_key_maps, **{
|
67
|
+
allow_destroy: true,
|
68
|
+
}
|
69
|
+
|
70
|
+
validates :default_value, **{
|
71
|
+
presence: {
|
72
|
+
unless: :column_model,
|
73
|
+
},
|
74
|
+
}
|
75
|
+
|
76
|
+
validates :method_name, **{
|
77
|
+
presence: true,
|
78
|
+
}
|
79
|
+
|
80
|
+
# validates :polymorphic, **{}
|
81
|
+
|
82
|
+
validates :primary_key, **{
|
83
|
+
presence: true,
|
84
|
+
}
|
85
|
+
|
86
|
+
validate :method_name_must_be_belongs_to_association, **{
|
87
|
+
if: ::Proc.new { |foreign_key| foreign_key.method_name.present? },
|
88
|
+
}
|
89
|
+
|
90
|
+
# @return [Regexp]
|
91
|
+
CAPTURE_GROUP_INDEX_REGEXP = ::Regexp.new("#{Regexp.quote('\\')}(0|[1-9][0-9]*)").freeze
|
92
|
+
|
93
|
+
# @return [String]
|
94
|
+
POLYMORPHIC_SEPARATOR = ':'.freeze
|
95
|
+
|
96
|
+
protected
|
97
|
+
|
98
|
+
# @param [ActiveRecord::Base, nil] base
|
99
|
+
# @return [Object, nil]
|
100
|
+
def _get_value(base = nil)
|
101
|
+
if base.nil?
|
102
|
+
nil
|
103
|
+
else
|
104
|
+
base.send(:"#{self.method_name}").try { |record|
|
105
|
+
record.try(:"#{self.primary_key}").try { |record_id|
|
106
|
+
if self.polymorphic?
|
107
|
+
record_class_name = record.class.name
|
108
|
+
record_table_name = ActsAsTable.adapter.tableize_for(self, record.class.name)
|
109
|
+
|
110
|
+
if record_table_name.nil? || (record_table_name.is_a?(::String) && record_table_name.include?(POLYMORPHIC_SEPARATOR))
|
111
|
+
raise "invalid record table name - #{record_table_name.inspect}"
|
112
|
+
end
|
113
|
+
|
114
|
+
[record_table_name, record_id].join(POLYMORPHIC_SEPARATOR)
|
115
|
+
else
|
116
|
+
record_id
|
117
|
+
end
|
118
|
+
}
|
119
|
+
}
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# @param [Object, nil] new_value
|
124
|
+
# @return [Object, nil]
|
125
|
+
def _modify_set_value_before_default(new_value = nil)
|
126
|
+
if new_value.nil?
|
127
|
+
new_value
|
128
|
+
elsif self.polymorphic?
|
129
|
+
# @return [Array<String>]
|
130
|
+
array = new_value.split(POLYMORPHIC_SEPARATOR)
|
131
|
+
|
132
|
+
# @return [String]
|
133
|
+
record_table_name = array[0]
|
134
|
+
|
135
|
+
# @return [String]
|
136
|
+
record_id = array[1..-1].join(POLYMORPHIC_SEPARATOR)
|
137
|
+
|
138
|
+
self.foreign_key_maps.each do |foreign_key_map|
|
139
|
+
# @return [Regexp]
|
140
|
+
source_value_as_regexp = foreign_key_map.source_value_as_regexp
|
141
|
+
|
142
|
+
unless (md = source_value_as_regexp.match(record_id)).nil?
|
143
|
+
return foreign_key_map.target_value.gsub(CAPTURE_GROUP_INDEX_REGEXP) { |other_md|
|
144
|
+
# @return [Integer]
|
145
|
+
i = other_md[1].to_i
|
146
|
+
|
147
|
+
[record_table_name, md[i]].join(POLYMORPHIC_SEPARATOR)
|
148
|
+
}
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
[record_table_name, record_id].join(POLYMORPHIC_SEPARATOR)
|
153
|
+
else
|
154
|
+
self.foreign_key_maps.each do |foreign_key_map|
|
155
|
+
# @return [Regexp]
|
156
|
+
source_value_as_regexp = foreign_key_map.source_value_as_regexp
|
157
|
+
|
158
|
+
unless (md = source_value_as_regexp.match(new_value)).nil?
|
159
|
+
return foreign_key_map.target_value.gsub(CAPTURE_GROUP_INDEX_REGEXP) { |other_md|
|
160
|
+
# @return [Integer]
|
161
|
+
i = other_md[1].to_i
|
162
|
+
|
163
|
+
md[i]
|
164
|
+
}
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
new_value
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# @param [ActiveRecord::Base, nil] base
|
173
|
+
# @param [Object, nil] new_value
|
174
|
+
# @return [Array<Object>]
|
175
|
+
def _set_value(base = nil, new_value = nil)
|
176
|
+
if base.nil?
|
177
|
+
[
|
178
|
+
nil,
|
179
|
+
false,
|
180
|
+
]
|
181
|
+
elsif self.polymorphic?
|
182
|
+
# @return [Object, nil]
|
183
|
+
orig_value = _get_value(base)
|
184
|
+
|
185
|
+
# @return [Class]
|
186
|
+
klass = self.record_model.class_name.constantize
|
187
|
+
|
188
|
+
# @return [ActiveRecord::Reflection::MacroAssociation]
|
189
|
+
reflection = klass.reflect_on_association(self.method_name)
|
190
|
+
|
191
|
+
unless reflection.polymorphic?
|
192
|
+
raise "invalid reflection (monomorphic) - #{reflection.inspect}"
|
193
|
+
end
|
194
|
+
|
195
|
+
# @return [Array<String>]
|
196
|
+
array = new_value.split(POLYMORPHIC_SEPARATOR)
|
197
|
+
|
198
|
+
# @return [String]
|
199
|
+
record_table_name = array[0]
|
200
|
+
|
201
|
+
# @return [String]
|
202
|
+
record_id = array[1..-1].join(POLYMORPHIC_SEPARATOR)
|
203
|
+
|
204
|
+
# @return [String]
|
205
|
+
record_class_name = ActsAsTable.adapter.classify_for(self, record_table_name)
|
206
|
+
|
207
|
+
# @return [ActiveRecord::Base, nil]
|
208
|
+
new_target_record = record_class_name.try(:constantize).try(:"find_by_#{self.primary_key}", record_id)
|
209
|
+
|
210
|
+
# @return [Boolean]
|
211
|
+
changed = !self.column_model.nil? && !(orig_value.nil? ? new_target_record.nil? : (new_target_record.nil? ? false : (orig_value == new_target_record.send(self.primary_key))))
|
212
|
+
|
213
|
+
[
|
214
|
+
new_target_record.try { |record| [record_table_name, base.send(:"#{self.method_name}=", record).try(self.primary_key)].join(POLYMORPHIC_SEPARATOR) },
|
215
|
+
changed,
|
216
|
+
]
|
217
|
+
else
|
218
|
+
# @return [Object, nil]
|
219
|
+
orig_value = _get_value(base)
|
220
|
+
|
221
|
+
# @return [Class]
|
222
|
+
klass = self.record_model.class_name.constantize
|
223
|
+
|
224
|
+
# @return [ActiveRecord::Reflection::MacroAssociation]
|
225
|
+
reflection = klass.reflect_on_association(self.method_name)
|
226
|
+
|
227
|
+
# @return [ActiveRecord::Base, nil]
|
228
|
+
new_target_record = reflection.klass.send(:"find_by_#{self.primary_key}", new_value)
|
229
|
+
|
230
|
+
# @return [Boolean]
|
231
|
+
changed = !self.column_model.nil? && !(orig_value.nil? ? new_target_record.nil? : (new_target_record.nil? ? false : (orig_value == new_target_record.send(self.primary_key))))
|
232
|
+
|
233
|
+
[
|
234
|
+
base.send(:"#{self.method_name}=", new_target_record).try(self.primary_key),
|
235
|
+
changed,
|
236
|
+
]
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
private
|
241
|
+
|
242
|
+
# @param [Class] klass
|
243
|
+
# @param [String] column_name
|
244
|
+
# @return [Boolean]
|
245
|
+
def _column?(klass, column_name)
|
246
|
+
klass.column_names.include?(column_name.to_s)
|
247
|
+
end
|
248
|
+
|
249
|
+
# @return [void]
|
250
|
+
def method_name_must_be_belongs_to_association
|
251
|
+
self.record_model.try { |record_model| record_model.class_name.constantize rescue nil }.try { |klass|
|
252
|
+
# @return [ActiveRecord::Reflection::MacroReflection]
|
253
|
+
reflection = klass.reflect_on_association(self.method_name)
|
254
|
+
|
255
|
+
if reflection.nil?
|
256
|
+
self.errors.add('method_name', :required)
|
257
|
+
elsif reflection.macro == :belongs_to
|
258
|
+
if self.polymorphic?
|
259
|
+
unless reflection.polymorphic?
|
260
|
+
self.errors.add('method_name', :invalid)
|
261
|
+
end
|
262
|
+
|
263
|
+
unless self.primary_key.eql?('id')
|
264
|
+
self.errors.add('primary_key', :invalid)
|
265
|
+
end
|
266
|
+
else
|
267
|
+
if reflection.polymorphic?
|
268
|
+
self.errors.add('method_name', :invalid)
|
269
|
+
end
|
270
|
+
|
271
|
+
self.primary_key.try { |primary_key|
|
272
|
+
if _column?(reflection.klass, primary_key)
|
273
|
+
self.default_value.try { |default_value|
|
274
|
+
unless reflection.klass.exists?({ primary_key => default_value, })
|
275
|
+
self.errors.add('default_value', :required)
|
276
|
+
end
|
277
|
+
}
|
278
|
+
|
279
|
+
self.foreign_key_maps.each do |foreign_key_map|
|
280
|
+
foreign_key_map.target_value.try { |target_value|
|
281
|
+
unless reflection.klass.exists?({ primary_key => target_value, })
|
282
|
+
foreign_key_map.errors.add('target_value', :required)
|
283
|
+
end
|
284
|
+
}
|
285
|
+
end
|
286
|
+
else
|
287
|
+
self.errors.add('primary_key', :required)
|
288
|
+
end
|
289
|
+
}
|
290
|
+
end
|
291
|
+
else
|
292
|
+
self.errors.add('method_name', :invalid)
|
293
|
+
end
|
294
|
+
}
|
295
|
+
|
296
|
+
return
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
module ActsAsTable
|
2
|
+
# ActsAsTable foreign key map.
|
3
|
+
#
|
4
|
+
# @!attribute [rw] extended
|
5
|
+
# Returns `true` if the source value for this ActsAsTable foreign key map is an extended regular expression. Otherwise, returns `false`.
|
6
|
+
#
|
7
|
+
# @return [Boolean]
|
8
|
+
# @!attribute [rw] ignore_case
|
9
|
+
# Returns `true` if the source value for this ActsAsTable foreign key map is a regular expression that ignores character case. Otherwise, returns `false`.
|
10
|
+
#
|
11
|
+
# @return [Boolean]
|
12
|
+
# @!attribute [rw] multiline
|
13
|
+
# Returns `true` if the source value for this ActsAsTable foreign key map is a multiline regular expression. Otherwise, returns `false`.
|
14
|
+
#
|
15
|
+
# @return [Boolean]
|
16
|
+
# @!attribute [rw] position
|
17
|
+
# Returns the position of this ActsAsTable foreign key map.
|
18
|
+
#
|
19
|
+
# @return [Integer]
|
20
|
+
# @!attribute [rw] regexp
|
21
|
+
# Returns `true` if the source value for this ActsAsTable foreign key map is a regular expression. Otherwise, returns `false`.
|
22
|
+
#
|
23
|
+
# @return [Boolean]
|
24
|
+
# @!attribute [rw] source_value
|
25
|
+
# Returns the source value for this ActsAsTable foreign key map.
|
26
|
+
#
|
27
|
+
# @return [Boolean]
|
28
|
+
# @!attribute [rw] target_value
|
29
|
+
# Returns the target value for this ActsAsTable foreign key map.
|
30
|
+
#
|
31
|
+
# @note If the source value for this ActsAsTable foreign key map is a regular expression, then the target value may reference any capture groups.
|
32
|
+
#
|
33
|
+
# @return [Boolean]
|
34
|
+
class ForeignKeyMap < ::ActiveRecord::Base
|
35
|
+
# @!parse
|
36
|
+
# include ActsAsTable::ValueProvider
|
37
|
+
# include ActsAsTable::ValueProviderAssociationMethods
|
38
|
+
|
39
|
+
self.table_name = ActsAsTable.foreign_key_maps_table
|
40
|
+
|
41
|
+
# Returns the ActsAsTable foreign key for this map.
|
42
|
+
belongs_to :foreign_key, **{
|
43
|
+
class_name: 'ActsAsTable::ForeignKey',
|
44
|
+
inverse_of: :foreign_key_maps,
|
45
|
+
required: true,
|
46
|
+
}
|
47
|
+
|
48
|
+
# validates :extended, **{}
|
49
|
+
|
50
|
+
# validates :ignore_case, **{}
|
51
|
+
|
52
|
+
# validates :multiline, **{}
|
53
|
+
|
54
|
+
validates :position, **{
|
55
|
+
numericality: {
|
56
|
+
greater_than_or_equal_to: 1,
|
57
|
+
only_integer: true,
|
58
|
+
},
|
59
|
+
presence: true,
|
60
|
+
uniqueness: {
|
61
|
+
scope: ['foreign_key_id'],
|
62
|
+
},
|
63
|
+
}
|
64
|
+
|
65
|
+
# validates :regexp, **{}
|
66
|
+
|
67
|
+
validates :source_value, **{
|
68
|
+
presence: true,
|
69
|
+
uniqueness: {
|
70
|
+
scope: ['foreign_key_id'],
|
71
|
+
},
|
72
|
+
}
|
73
|
+
|
74
|
+
validates :target_value, **{
|
75
|
+
presence: true,
|
76
|
+
}
|
77
|
+
|
78
|
+
validate :source_value_as_regexp_must_be_valid, **{
|
79
|
+
if: ::Proc.new { |foreign_key_map| foreign_key_map.source_value.present? },
|
80
|
+
}
|
81
|
+
|
82
|
+
# Returns the source value for this ActsAsTable foreign key map as a regular expression.
|
83
|
+
#
|
84
|
+
# @return [Regexp]
|
85
|
+
# @raise [RegexpError]
|
86
|
+
def source_value_as_regexp
|
87
|
+
# @return [String]
|
88
|
+
pattern = self.source_value.to_s
|
89
|
+
|
90
|
+
unless self.regexp?
|
91
|
+
pattern = "\\A#{::Regexp.quote(pattern)}\\z"
|
92
|
+
end
|
93
|
+
|
94
|
+
# @return [Integer]
|
95
|
+
flags = {
|
96
|
+
:extended => :EXTENDED,
|
97
|
+
:ignore_case => :IGNORECASE,
|
98
|
+
:multiline => :MULTILINE,
|
99
|
+
}.each_pair.inject(0) { |acc, pair|
|
100
|
+
method_name, const_name = *pair
|
101
|
+
|
102
|
+
self.send(:"#{method_name}?") ? (acc | ::Regexp.const_get(const_name, false)) : acc
|
103
|
+
}
|
104
|
+
|
105
|
+
::Regexp.new(pattern, flags)
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
|
110
|
+
# @return [void]
|
111
|
+
def source_value_as_regexp_must_be_valid
|
112
|
+
begin
|
113
|
+
self.source_value_as_regexp
|
114
|
+
rescue ::RegexpError
|
115
|
+
self.errors.add('source_value', :invalid)
|
116
|
+
end
|
117
|
+
|
118
|
+
return
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module ActsAsTable
|
2
|
+
# ActsAsTable collection macro association.
|
3
|
+
#
|
4
|
+
# @!attribute [rw] macro
|
5
|
+
# Returns the symbolic name for the macro for this ActsAsTable collection macro association.
|
6
|
+
#
|
7
|
+
# @note The macro must be either `:has_many` or `:has_and_belongs_to_many`.
|
8
|
+
#
|
9
|
+
# @return [String]
|
10
|
+
# @!attribute [rw] method_name
|
11
|
+
# Returns the method name for this ActsAsTable collection macro association.
|
12
|
+
#
|
13
|
+
# @return [String]
|
14
|
+
class HasMany < ::ActiveRecord::Base
|
15
|
+
# @!parse
|
16
|
+
# include ActsAsTable::ValueProvider
|
17
|
+
# include ActsAsTable::ValueProviderAssociationMethods
|
18
|
+
|
19
|
+
self.table_name = ActsAsTable.has_manies_table
|
20
|
+
|
21
|
+
# Returns the ActsAsTable row model for this ActsAsTable collection macro association.
|
22
|
+
belongs_to :row_model, **{
|
23
|
+
class_name: 'ActsAsTable::RowModel',
|
24
|
+
inverse_of: :has_manies,
|
25
|
+
required: true,
|
26
|
+
}
|
27
|
+
|
28
|
+
# Returns the source ActsAsTable record model for this ActsAsTable collection macro association.
|
29
|
+
belongs_to :source_record_model, **{
|
30
|
+
class_name: 'ActsAsTable::RecordModel',
|
31
|
+
inverse_of: :has_manies_as_source,
|
32
|
+
required: true,
|
33
|
+
}
|
34
|
+
|
35
|
+
# Returns the targets for this ActsAsTable collection macro association.
|
36
|
+
has_many :has_many_targets, -> { order(position: :asc) }, **{
|
37
|
+
autosave: true,
|
38
|
+
class_name: 'ActsAsTable::HasManyTarget',
|
39
|
+
dependent: :destroy,
|
40
|
+
foreign_key: 'has_many_id',
|
41
|
+
inverse_of: :has_many,
|
42
|
+
validate: true,
|
43
|
+
}
|
44
|
+
|
45
|
+
accepts_nested_attributes_for :has_many_targets, **{
|
46
|
+
allow_destroy: true,
|
47
|
+
}
|
48
|
+
|
49
|
+
validates :macro, **{
|
50
|
+
inclusion: {
|
51
|
+
in: ['has_many', 'has_and_belongs_to_many'],
|
52
|
+
},
|
53
|
+
presence: true,
|
54
|
+
}
|
55
|
+
|
56
|
+
validates :method_name, **{
|
57
|
+
presence: true,
|
58
|
+
}
|
59
|
+
|
60
|
+
validate :macro_and_method_name_must_be_valid_association, **{
|
61
|
+
if: ::Proc.new { |has_many| has_many.macro.present? && has_many.method_name.present? },
|
62
|
+
}
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
# @return [void]
|
67
|
+
def macro_and_method_name_must_be_valid_association
|
68
|
+
self.source_record_model.try { |record_model| record_model.class_name.constantize rescue nil }.try { |source_klass|
|
69
|
+
# @return [ActiveRecord::Reflection::MacroReflection]
|
70
|
+
reflection = source_klass.reflect_on_association(self.method_name)
|
71
|
+
|
72
|
+
if reflection.nil?
|
73
|
+
self.errors.add('method_name', :required)
|
74
|
+
elsif self.macro.eql?(reflection.macro.to_s)
|
75
|
+
self.has_many_targets.each do |has_many_target|
|
76
|
+
has_many_target.record_model.try { |record_model| record_model.class_name.constantize rescue nil }.try { |target_klass|
|
77
|
+
unless reflection.klass == target_klass
|
78
|
+
has_many_target.errors.add('record_model_id', :invalid)
|
79
|
+
end
|
80
|
+
}
|
81
|
+
end
|
82
|
+
else
|
83
|
+
self.errors.add('method_name', :invalid)
|
84
|
+
end
|
85
|
+
}
|
86
|
+
|
87
|
+
return
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|