duty_free 1.0.3 → 1.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/duty_free/extensions.rb +122 -117
- data/lib/duty_free/suggest_template.rb +11 -11
- data/lib/duty_free/version_number.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f6139333a59c0d3cfb29003ee8d076214906b49270f05de439a260dcf6db227b
|
4
|
+
data.tar.gz: 2e129dec49e960970b8116983d7b483fa0144511d315586f12a15a2df3ca52b7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 553fe2590a1803cf52b166290b6c2d2525f58d59a45bba5f1b2f1e1a8e6be42451f5e6642c1971195816bdbe8a3573f5327f5b1f9fedf46abe57762bc1131fd4
|
7
|
+
data.tar.gz: 1ded83dc81de148793c4e98ad809e31efff083b650cd69af07b99e305f0ada3e1a4ccc749a00569838397d018ff1817d40a8a2e89a7ae0964cc8ea4afe4f8ef6
|
data/lib/duty_free/extensions.rb
CHANGED
@@ -79,8 +79,8 @@ module DutyFree
|
|
79
79
|
|
80
80
|
# With an array of incoming data, the first row having column names, perform the import
|
81
81
|
def df_import(data, import_template = nil)
|
82
|
-
|
83
|
-
|
82
|
+
instance_variable_set(:@defined_uniques, nil)
|
83
|
+
instance_variable_set(:@valid_uniques, nil)
|
84
84
|
|
85
85
|
import_template ||= if constants.include?(:IMPORT_TEMPLATE)
|
86
86
|
self::IMPORT_TEMPLATE
|
@@ -105,6 +105,7 @@ module DutyFree
|
|
105
105
|
devise_class = ''
|
106
106
|
ret = nil
|
107
107
|
|
108
|
+
# Multi-tenancy gem Apartment can be used if there are separate schemas per tenant
|
108
109
|
reference_models = if Object.const_defined?('Apartment')
|
109
110
|
Apartment.excluded_models
|
110
111
|
else
|
@@ -121,10 +122,13 @@ module DutyFree
|
|
121
122
|
|
122
123
|
# Did they give us a filename?
|
123
124
|
if data.is_a?(String)
|
124
|
-
|
125
|
+
# Filenames with full paths can not be longer than 4096 characters, and can not
|
126
|
+
# include newline characters
|
127
|
+
data = if data.length <= 4096 && !data.index('\n')
|
125
128
|
File.open(data)
|
126
129
|
else
|
127
|
-
#
|
130
|
+
# Any multi-line string is likely CSV data
|
131
|
+
# %%% Test to see if TAB characters are present on the first line, instead of commas
|
128
132
|
CSV.new(data)
|
129
133
|
end
|
130
134
|
end
|
@@ -143,8 +147,15 @@ module DutyFree
|
|
143
147
|
# Will show as just one transaction when using auditing solutions such as PaperTrail
|
144
148
|
ActiveRecord::Base.transaction do
|
145
149
|
# Check to see if they want to do anything before the whole import
|
146
|
-
if
|
147
|
-
|
150
|
+
# First if defined in the import_template, then if there is a method in the class,
|
151
|
+
# and finally (not yet implemented) a generic global before_import
|
152
|
+
my_before_import = import_template[:before_import]
|
153
|
+
my_before_import ||= respond_to?(:before_import) && method(:before_import)
|
154
|
+
# my_before_import ||= some generic my_before_import
|
155
|
+
if my_before_import
|
156
|
+
last_arg_idx = my_before_import.parameters.length - 1
|
157
|
+
arguments = [data, import_template][0..last_arg_idx]
|
158
|
+
data = ret if (ret = my_before_import.call(*arguments)).is_a?(Enumerable)
|
148
159
|
end
|
149
160
|
col_list = nil
|
150
161
|
data.each_with_index do |row, row_num|
|
@@ -178,8 +189,8 @@ module DutyFree
|
|
178
189
|
# %%% Will the uniques saved into @defined_uniques here just get redefined later
|
179
190
|
# after the next line, the map! with clean to change out the alias names? So we can't yet set
|
180
191
|
# col_list?
|
181
|
-
defined_uniques(uniques, cols, cols.join('|'), starred)
|
182
192
|
cols.map! { |col| ::DutyFree::Util._clean_name(col, import_template[:as]) } # %%%
|
193
|
+
defined_uniques(uniques, cols, cols.join('|'), starred)
|
183
194
|
# Make sure that at least half of them match what we know as being good column names
|
184
195
|
template_column_objects = ::DutyFree::Extensions._recurse_def(self, import_template[:all], import_template).first
|
185
196
|
cols.each_with_index do |col, idx|
|
@@ -187,9 +198,7 @@ module DutyFree
|
|
187
198
|
keepers[idx] = template_column_objects.find { |col_obj| col_obj.titleize == col }
|
188
199
|
# puts "Could not find a match for column #{idx + 1}, #{col}" if keepers[idx].nil?
|
189
200
|
end
|
190
|
-
if keepers.length < (cols.length / 2) - 1
|
191
|
-
raise ::DutyFree::LessThanHalfAreMatchingColumnsError, I18n.t('import.altered_import_template_coumns')
|
192
|
-
end
|
201
|
+
raise ::DutyFree::LessThanHalfAreMatchingColumnsError, I18n.t('import.altered_import_template_coumns') if keepers.length < (cols.length / 2) - 1
|
193
202
|
|
194
203
|
# Returns just the first valid unique lookup set if there are multiple
|
195
204
|
valid_unique = find_existing(uniques, cols, starred, import_template, keepers, false)
|
@@ -206,14 +215,11 @@ module DutyFree
|
|
206
215
|
s << if v.last.is_a?(Array)
|
207
216
|
v.last[0].where(v.last[1] => row[v.last[2]]).limit(1).pluck(MAX_ID).first.to_s
|
208
217
|
else
|
209
|
-
binding.pry if v.last.nil?
|
210
218
|
row[v.last].to_s
|
211
219
|
end
|
212
220
|
end
|
213
221
|
# Check to see if they want to preprocess anything
|
214
|
-
if @before_process ||= import_template[:before_process]
|
215
|
-
existing_unique = @before_process.call(valid_unique, existing_unique)
|
216
|
-
end
|
222
|
+
existing_unique = @before_process.call(valid_unique, existing_unique) if @before_process ||= import_template[:before_process]
|
217
223
|
obj = if existing.include?(existing_unique)
|
218
224
|
find(existing[existing_unique])
|
219
225
|
else
|
@@ -227,7 +233,6 @@ module DutyFree
|
|
227
233
|
sub_objects = {}
|
228
234
|
this_path = nil
|
229
235
|
keepers.each do |key, v|
|
230
|
-
klass = nil
|
231
236
|
next if v.nil?
|
232
237
|
|
233
238
|
# Not the same as the last path?
|
@@ -242,7 +247,6 @@ module DutyFree
|
|
242
247
|
modded_obj.save if sub_obj&.valid?
|
243
248
|
end
|
244
249
|
elsif sub_obj&.valid?
|
245
|
-
# binding.pry if sub_obj.is_a?(Employee) && sub_obj.first_name == 'Andrew'
|
246
250
|
sub_obj.save
|
247
251
|
end
|
248
252
|
end
|
@@ -285,28 +289,20 @@ module DutyFree
|
|
285
289
|
# such as importing orders and having employees come along :)
|
286
290
|
# if sub_obj.class == klass
|
287
291
|
# trim_prefix = ''
|
288
|
-
# # binding.pry
|
289
292
|
# end
|
290
293
|
# %%% Maybe instead of passing in "klass" we can give the belongs_to association and build through that instead,
|
291
294
|
# allowing us to nix the klass.new(criteria) line below.
|
292
295
|
trim_prefix = v.titleize[0..-(v.name.length + 2)]
|
293
296
|
trim_prefix << ' ' unless trim_prefix.blank?
|
294
|
-
if klass == sub_obj.class # Self-referencing thing pointing to us?
|
295
|
-
|
296
|
-
|
297
|
-
# assoc
|
298
|
-
sub_bt, criteria = klass.find_existing(uniques, sub_cols, starred, import_template, keepers, nil, row, klass, all, '')
|
299
|
-
else
|
300
|
-
sub_bt, criteria = klass.find_existing(uniques, cols, starred, import_template, keepers, nil, row, klass, all, trim_prefix)
|
301
|
-
end
|
297
|
+
# if klass == sub_obj.class # Self-referencing thing pointing to us?
|
298
|
+
# %%% This should be more general than just for self-referencing things.
|
299
|
+
sub_bt, criteria = klass.find_existing(uniques, cols, starred, import_template, keepers, nil, row, klass, all, trim_prefix)
|
302
300
|
rescue ::DutyFree::NoUniqueColumnError
|
303
301
|
sub_unique = nil
|
304
302
|
end
|
305
303
|
# Self-referencing shouldn't build a new one if it couldn't find one
|
306
|
-
# %%% Can criteria really ever be
|
307
|
-
unless klass == sub_obj.class && criteria.empty?
|
308
|
-
sub_bt ||= klass.new(criteria || {})
|
309
|
-
end
|
304
|
+
# %%% Can criteria really ever be empty anymore?
|
305
|
+
sub_bt ||= klass.new(criteria || {}) unless klass == sub_obj.class && criteria.empty?
|
310
306
|
sub_obj.send("#{path_part}=", sub_bt)
|
311
307
|
sub_bt
|
312
308
|
end
|
@@ -326,8 +322,6 @@ module DutyFree
|
|
326
322
|
trim_prefix = v.titleize[start..-(v.name.length + 2)]
|
327
323
|
trim_prefix << ' ' unless trim_prefix.blank?
|
328
324
|
klass = sub_next.klass
|
329
|
-
# binding.pry if klass.name == 'OrderDetail'
|
330
|
-
|
331
325
|
# assoc.inverse_of is the belongs_to side of the has_many train we came in here on.
|
332
326
|
sub_hm, criteria = klass.find_existing(uniques, cols, starred, import_template, keepers, assoc.inverse_of, row, sub_next, all, trim_prefix)
|
333
327
|
|
@@ -347,14 +341,11 @@ module DutyFree
|
|
347
341
|
sub_objects[this_path] = sub_next if this_path.present?
|
348
342
|
end
|
349
343
|
end
|
350
|
-
#
|
351
|
-
sub_obj = sub_next #if sub_next
|
344
|
+
sub_obj = sub_next # if sub_next
|
352
345
|
end
|
353
|
-
# binding.pry if sub_obj.nil?
|
354
346
|
next if sub_obj.nil?
|
355
347
|
|
356
|
-
sym = "#{v.name}=".to_sym
|
357
|
-
next unless sub_obj.respond_to?(sym)
|
348
|
+
next unless sub_obj.respond_to?(sym = "#{v.name}=".to_sym)
|
358
349
|
|
359
350
|
col_type = (sub_class = sub_obj.class).columns_hash[v.name.to_s]&.type
|
360
351
|
if col_type.nil? && (virtual_columns = import_template[:virtual_columns]) &&
|
@@ -364,16 +355,15 @@ module DutyFree
|
|
364
355
|
if col_type == :boolean
|
365
356
|
if row[key].nil?
|
366
357
|
# Do nothing when it's nil
|
367
|
-
elsif %w[yes y].include?(row[key]&.downcase) # Used to cover '
|
358
|
+
elsif %w[true t yes y].include?(row[key]&.downcase) # Used to cover 'on'
|
368
359
|
row[key] = true
|
369
|
-
elsif %w[no n].include?(row[key]&.downcase) # Used to cover '
|
360
|
+
elsif %w[false f no n].include?(row[key]&.downcase) # Used to cover 'off'
|
370
361
|
row[key] = false
|
371
362
|
else
|
372
363
|
row_errors[v.name] ||= []
|
373
364
|
row_errors[v.name] << "Boolean value \"#{row[key]}\" in column #{key + 1} not recognized"
|
374
365
|
end
|
375
366
|
end
|
376
|
-
# binding.pry if v.name.to_s == 'first_name' && sub_obj.first_name == 'Nancy'
|
377
367
|
sub_obj.send(sym, row[key])
|
378
368
|
# else
|
379
369
|
# puts " #{sub_class.name} doesn't respond to #{sym}"
|
@@ -423,10 +413,18 @@ module DutyFree
|
|
423
413
|
s += v.last[1..-1].map { |line_num| { line_num => v.first } } if v.last.count > 1
|
424
414
|
s
|
425
415
|
end
|
426
|
-
# Check to see if they want to do anything after the import
|
427
416
|
ret = { inserted: inserts, updated: updates, duplicates: duplicates, errors: errors }
|
428
|
-
|
429
|
-
|
417
|
+
|
418
|
+
# Check to see if they want to do anything after the import
|
419
|
+
# First if defined in the import_template, then if there is a method in the class,
|
420
|
+
# and finally (not yet implemented) a generic global after_import
|
421
|
+
my_after_import = import_template[:after_import]
|
422
|
+
my_after_import ||= respond_to?(:after_import) && method(:after_import)
|
423
|
+
# my_after_import ||= some generic my_after_import
|
424
|
+
if my_after_import
|
425
|
+
last_arg_idx = my_after_import.parameters.length - 1
|
426
|
+
arguments = [ret][0..last_arg_idx]
|
427
|
+
ret = ret2 if (ret2 = my_after_import.call(*arguments)).is_a?(Hash)
|
430
428
|
end
|
431
429
|
end
|
432
430
|
ret
|
@@ -435,89 +433,46 @@ module DutyFree
|
|
435
433
|
# For use with importing, based on the provided column list calculate all valid combinations
|
436
434
|
# of unique columns. If there is no valid combination, throws an error.
|
437
435
|
# Returns an object found by this means.
|
438
|
-
def find_existing(uniques, cols, starred, import_template, keepers, train_we_came_in_here_on,
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
template_column_objects = ::DutyFree::Extensions._recurse_def(self, all || import_template[:all], import_template).first
|
446
|
-
available = if trim_prefix.blank?
|
447
|
-
template_column_objects.select { |col| col.pre_prefix.blank? && col.prefix.blank? }
|
448
|
-
else
|
449
|
-
trim_prefix_snake = trim_prefix.downcase.tr(' ', '_')
|
450
|
-
template_column_objects.select do |col|
|
451
|
-
this_prefix = ::DutyFree::Util._prefix_join([col.pre_prefix, col.prefix], '_').tr('.', '_')
|
452
|
-
trim_prefix_snake == "#{this_prefix}_"
|
453
|
-
end
|
454
|
-
end.map { |avail| avail.name.to_s.titleize }
|
455
|
-
vus = defined_uniques(uniques, cols, nil, starred).select do |k, _v|
|
456
|
-
is_good = true
|
457
|
-
k.each do |k_col|
|
458
|
-
unless k_col.start_with?(trim_prefix) && available.include?(k_col[col_name_offset..-1])
|
459
|
-
is_good = false
|
460
|
-
break
|
461
|
-
end
|
462
|
-
end
|
463
|
-
is_good
|
464
|
-
end
|
465
|
-
@valid_uniques[col_list] = vus
|
466
|
-
end
|
467
|
-
|
468
|
-
# Make sure they have at least one unique combination to take cues from
|
469
|
-
ret = {}
|
470
|
-
unless vus.empty? # raise NoUniqueColumnError.new(I18n.t('import.no_unique_column_error'))
|
471
|
-
# Convert the first entry to a simplified hash, such as:
|
472
|
-
# {[:investigator_institutions_name, :investigator_institutions_email] => [8, 9], ...}
|
473
|
-
# to {:name => 8, :email => 9}
|
474
|
-
key, val = vus.first
|
475
|
-
key.each_with_index do |k, idx|
|
476
|
-
ret[k[col_name_offset..-1].downcase.tr(' ', '_').to_sym] = val[idx] if k.start_with?(trim_prefix)
|
436
|
+
def find_existing(uniques, cols, starred, import_template, keepers, train_we_came_in_here_on,
|
437
|
+
row = nil, klass_or_collection = nil, all = nil, trim_prefix = '')
|
438
|
+
unless trim_prefix.blank?
|
439
|
+
cols = cols.map { |c| c.start_with?(trim_prefix) ? c[trim_prefix.length..-1] : nil }
|
440
|
+
starred = starred.each_with_object([]) do |v, s|
|
441
|
+
s << v[trim_prefix.length..-1] if v.start_with?(trim_prefix)
|
442
|
+
s
|
477
443
|
end
|
478
444
|
end
|
479
445
|
|
480
|
-
#
|
481
|
-
#
|
482
|
-
# be found or built first before OrderDetail.)
|
483
|
-
# Might have to do a deferred save kind of thing, and also make sure the product stuff came first
|
484
|
-
# before the other stuff
|
485
|
-
|
486
|
-
# Find by all corresponding columns
|
487
|
-
|
488
|
-
# Add in any foreign key stuff we can find from other belongs_to associations
|
489
|
-
# %%% This is starting to look like the other BelongsToAssociation code above around line
|
490
|
-
# 697, so it really needs to be turned into something recursive instead of this two-layer
|
491
|
-
# thick thing at best.
|
492
|
-
|
493
|
-
# First check the belongs_tos
|
446
|
+
# First add in foreign key stuff we can find from belongs_to associations (other than the
|
447
|
+
# one we might have arrived here upon).
|
494
448
|
criteria = {}
|
495
449
|
bt_criteria = {}
|
496
450
|
bt_criteria_all_nil = true
|
497
451
|
bt_col_indexes = []
|
452
|
+
available_bts = []
|
498
453
|
only_valid_uniques = (train_we_came_in_here_on == false)
|
454
|
+
uniq_lookups = {}
|
455
|
+
# %%% Ultimately may consider making this recursive
|
499
456
|
bts = reflect_on_all_associations.each_with_object([]) do |sn_assoc, s|
|
500
457
|
if sn_assoc.is_a?(ActiveRecord::Reflection::BelongsToReflection) &&
|
501
|
-
(!train_we_came_in_here_on || sn_assoc != train_we_came_in_here_on)
|
502
|
-
# sn_assoc.klass != self # Omit stuff pointing to us (like self-referencing stuff)
|
458
|
+
(!train_we_came_in_here_on || sn_assoc != train_we_came_in_here_on)
|
503
459
|
# %%% Make sure there's a starred column we know about from this one
|
504
|
-
|
460
|
+
uniq_lookups[sn_assoc.foreign_key] = nil if only_valid_uniques
|
505
461
|
s << sn_assoc
|
506
462
|
end
|
507
463
|
s
|
508
464
|
end
|
509
465
|
bts.each do |sn_bt|
|
510
466
|
# This search prefix becomes something like "Order Details Product "
|
511
|
-
# binding.pry
|
512
467
|
cols.each_with_index do |bt_col, idx|
|
513
468
|
next if bt_col_indexes.include?(idx) ||
|
514
469
|
!bt_col&.start_with?(trim_prefix + "#{sn_bt.name.to_s.underscore.tr('_', ' ').titleize} ")
|
515
470
|
|
471
|
+
available_bts << bt_col
|
516
472
|
fk_id = if row
|
517
473
|
# Max ID so if there are multiple, only the most recent one is picked.
|
518
474
|
# %%% Need to stack these up in case there are multiple
|
519
475
|
# (like first_name, last_name on a referenced employee)
|
520
|
-
# binding.pry
|
521
476
|
sn_bt.klass.where(keepers[idx].name => row[idx]).limit(1).pluck(MAX_ID).first
|
522
477
|
else
|
523
478
|
[sn_bt.klass, keepers[idx].name, idx]
|
@@ -529,46 +484,93 @@ module DutyFree
|
|
529
484
|
bt_criteria[(fk_name = sn_bt.foreign_key)] = fk_id
|
530
485
|
# Add to our criteria if this belongs_to is required
|
531
486
|
# %%% Rails older than 5.0 handles this stuff differently!
|
532
|
-
|
487
|
+
if sn_bt.options[:optional] || !sn_bt.klass.belongs_to_required_by_default
|
488
|
+
# Should not have this fk as a requirement
|
489
|
+
uniq_lookups.delete(fk_name) if only_valid_uniques && uniq_lookups.include?(fk_name)
|
490
|
+
else # Add to the criteria
|
533
491
|
criteria[fk_name] = fk_id
|
534
|
-
else # Should not have this fk as a requirement
|
535
|
-
ret.delete(fk_name) if only_valid_uniques && ret.include?(fk_name)
|
536
492
|
end
|
537
493
|
end
|
538
494
|
end
|
539
495
|
|
496
|
+
@valid_uniques ||= {} # Fancy memoisation
|
497
|
+
col_list = cols.join('|')
|
498
|
+
unless (vus = @valid_uniques[col_list])
|
499
|
+
# Find all unique combinations that are available based on incoming columns, and
|
500
|
+
# pair them up with column number mappings.
|
501
|
+
template_column_objects = ::DutyFree::Extensions._recurse_def(self, all || import_template[:all], import_template).first
|
502
|
+
available = if trim_prefix.blank?
|
503
|
+
template_column_objects.select { |col| col.pre_prefix.blank? && col.prefix.blank? }
|
504
|
+
else
|
505
|
+
trim_prefix_snake = trim_prefix.downcase.tr(' ', '_')
|
506
|
+
template_column_objects.select do |col|
|
507
|
+
this_prefix = ::DutyFree::Util._prefix_join([col.pre_prefix, col.prefix], '_').tr('.', '_')
|
508
|
+
trim_prefix_snake == "#{this_prefix}_"
|
509
|
+
end
|
510
|
+
end.map { |avail| avail.name.to_s.titleize }
|
511
|
+
vus = defined_uniques(uniques, cols, nil, starred).select do |k, _v|
|
512
|
+
is_good = true
|
513
|
+
k.each do |k_col|
|
514
|
+
unless available.include?(k_col) || available_bts.include?(k_col)
|
515
|
+
is_good = false
|
516
|
+
break
|
517
|
+
end
|
518
|
+
end
|
519
|
+
is_good
|
520
|
+
end
|
521
|
+
@valid_uniques[col_list] = vus
|
522
|
+
end
|
523
|
+
|
524
|
+
# Make sure they have at least one unique combination to take cues from
|
525
|
+
unless vus.empty? # raise NoUniqueColumnError.new(I18n.t('import.no_unique_column_error'))
|
526
|
+
# Convert the first entry to a simplified hash, such as:
|
527
|
+
# {[:investigator_institutions_name, :investigator_institutions_email] => [8, 9], ...}
|
528
|
+
# to {:name => 8, :email => 9}
|
529
|
+
key, val = vus.first
|
530
|
+
key.each_with_index do |k, idx|
|
531
|
+
next if available_bts.include?(k) # These will be provided in criteria, and not uniq_lookups
|
532
|
+
|
533
|
+
# uniq_lookups[k[trim_prefix.length..-1].downcase.tr(' ', '_').to_sym] = val[idx] if k.start_with?(trim_prefix)
|
534
|
+
uniq_lookups[k.downcase.tr(' ', '_').to_sym] = val[idx]
|
535
|
+
end
|
536
|
+
end
|
537
|
+
|
538
|
+
# Find by all corresponding columns
|
539
|
+
|
540
540
|
new_criteria_all_nil = bt_criteria_all_nil
|
541
|
-
|
542
|
-
|
543
|
-
next if bt_col_indexes.include?(v
|
541
|
+
unless only_valid_uniques
|
542
|
+
uniq_lookups.each do |k, v|
|
543
|
+
next if bt_col_indexes.include?(v)
|
544
544
|
|
545
|
-
|
546
|
-
|
545
|
+
if (row_value = row[v])
|
546
|
+
new_criteria_all_nil = false
|
547
|
+
criteria[k.to_sym] = row_value
|
548
|
+
end
|
547
549
|
end
|
548
550
|
end
|
549
551
|
|
550
552
|
# Short-circuiting this to only get back the valid_uniques?
|
551
|
-
return
|
553
|
+
return uniq_lookups.merge(criteria) if only_valid_uniques
|
552
554
|
|
553
|
-
# binding.pry if obj.is_a?(Order)
|
554
555
|
# If there's nothing to match upon then we're out
|
555
556
|
return [nil, {}] if new_criteria_all_nil
|
556
557
|
|
557
558
|
# With this criteria, find any matching has_many row we can so we can update it
|
558
|
-
|
559
|
+
# First try looking it up through ActiveRecord
|
560
|
+
found_object = klass_or_collection.find_by(criteria)
|
561
|
+
# If not successful, such as when fields are exposed via helper methods instead of being
|
562
|
+
# real columns in the database tables, try this more intensive routine.
|
563
|
+
found_object ||= klass_or_collection.find do |obj|
|
559
564
|
is_good = true
|
560
565
|
criteria.each do |k, v|
|
561
|
-
if
|
566
|
+
if obj.send(k).to_s != v.to_s
|
562
567
|
is_good = false
|
563
568
|
break
|
564
569
|
end
|
565
570
|
end
|
566
571
|
is_good
|
567
572
|
end
|
568
|
-
|
569
|
-
# %%% Should we perhaps do this first before the more intensive find routine above?
|
570
|
-
sub_hm = obj.find_by(criteria) if sub_hm.nil?
|
571
|
-
[sub_hm, criteria.merge(bt_criteria)]
|
573
|
+
[found_object, criteria.merge(bt_criteria)]
|
572
574
|
end
|
573
575
|
|
574
576
|
private
|
@@ -601,7 +603,10 @@ module DutyFree
|
|
601
603
|
end
|
602
604
|
end
|
603
605
|
end
|
604
|
-
|
606
|
+
if defined_uniq.empty?
|
607
|
+
(starred - utilised.keys).each { |star| defined_uniq[[star]] = [cols.index(star)] }
|
608
|
+
# %%% puts "Tried to establish #{defined_uniq.inspect}"
|
609
|
+
end
|
605
610
|
@defined_uniques[col_list] = defined_uniq
|
606
611
|
end
|
607
612
|
defined_uniq
|
@@ -53,13 +53,9 @@ module DutyFree
|
|
53
53
|
# Always process belongs_to, and also process has_one and has_many if do_has_many is chosen.
|
54
54
|
# Skip any HMT or HABTM. (Maybe break out HABTM into a combo HM and BT in the future.)
|
55
55
|
if is_habtm
|
56
|
-
unless ActiveRecord::Base.connection.table_exists?(assoc.join_table)
|
57
|
-
puts "* In the #{this_klass.name} model there's a problem with: \"has_and_belongs_to_many :#{assoc.name}\" because join table \"#{assoc.join_table}\" does not exist. You can create it with a create_join_table migration."
|
58
|
-
end
|
56
|
+
puts "* In the #{this_klass.name} model there's a problem with: \"has_and_belongs_to_many :#{assoc.name}\" because join table \"#{assoc.join_table}\" does not exist. You can create it with a create_join_table migration." unless ActiveRecord::Base.connection.table_exists?(assoc.join_table)
|
59
57
|
# %%% Search for other associative candidates to use instead of this HABTM contraption
|
60
|
-
if assoc.options.include?(:through)
|
61
|
-
puts "* In the #{this_klass.name} model there's a problem with: \"has_and_belongs_to_many :#{assoc.name}\" because it includes \"through: #{assoc.options[:through].inspect}\" which is pointless and should be removed."
|
62
|
-
end
|
58
|
+
puts "* In the #{this_klass.name} model there's a problem with: \"has_and_belongs_to_many :#{assoc.name}\" because it includes \"through: #{assoc.options[:through].inspect}\" which is pointless and should be removed." if assoc.options.include?(:through)
|
63
59
|
end
|
64
60
|
if (is_through = assoc.is_a?(ActiveRecord::Reflection::ThroughReflection)) && assoc.options.include?(:as)
|
65
61
|
puts "* In the #{this_klass.name} model there's a problem with: \"has_many :#{assoc.name} through: #{assoc.options[:through].inspect}\" because it also includes \"as: #{assoc.options[:as].inspect}\", so please choose either for this line to be a \"has_many :#{assoc.name} through:\" or to be a polymorphic \"has_many :#{assoc.name} as:\". It can't be both."
|
@@ -203,9 +199,7 @@ module DutyFree
|
|
203
199
|
|
204
200
|
# Requireds takes its cues from all attributes having a presence validator
|
205
201
|
requireds = _find_requireds(klass)
|
206
|
-
if priority_excluded_columns
|
207
|
-
klass_columns = klass_columns.reject { |col| priority_excluded_columns.include?(col.name) }
|
208
|
-
end
|
202
|
+
klass_columns = klass_columns.reject { |col| priority_excluded_columns.include?(col.name) } if priority_excluded_columns
|
209
203
|
excluded_columns = %w[created_at updated_at deleted_at]
|
210
204
|
unique = [(
|
211
205
|
# Find the first text field of a required if one exists
|
@@ -240,8 +234,14 @@ module DutyFree
|
|
240
234
|
if klass.columns.map(&:name).include?(attrib)
|
241
235
|
s << attrib
|
242
236
|
else
|
243
|
-
|
244
|
-
|
237
|
+
bt_names = klass.reflect_on_all_associations.each_with_object([]) do |assoc, names|
|
238
|
+
names << assoc.name.to_s if assoc.is_a?(ActiveRecord::Reflection::BelongsToReflection)
|
239
|
+
names
|
240
|
+
end
|
241
|
+
unless bt_names.include?(attrib)
|
242
|
+
puts "* In the #{klass.name} model \"validates_presence_of :#{attrib}\" should be removed as it does not refer to any existing column."
|
243
|
+
errored_columns << klass_col
|
244
|
+
end
|
245
245
|
end
|
246
246
|
end
|
247
247
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: duty_free
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lorin Thwaits
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-11-
|
11
|
+
date: 2020-11-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|