duty_free 1.0.3 → 1.0.4
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 +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
|