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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4451cbb29d90fb32347b1ff91e91a249da97769e7a64f2524efa912b8971bf86
4
- data.tar.gz: ee3b06059aa89be48329ef48605287e8cb1725dd9f61460d9b3d044354405540
3
+ metadata.gz: f6139333a59c0d3cfb29003ee8d076214906b49270f05de439a260dcf6db227b
4
+ data.tar.gz: 2e129dec49e960970b8116983d7b483fa0144511d315586f12a15a2df3ca52b7
5
5
  SHA512:
6
- metadata.gz: 953bb38945daf16d0f22daa921ad1e0f46881583d51145a59b1983869da8d79c0675640677f1774dbdb9321695aeb69dc29dd4f66250704be0199fed33ab84b6
7
- data.tar.gz: 8e3a0c166acb9bc22919218764e1e39ffa9d495e22ea93eaeb8ef6810b545a99f6af08bf594cc3958e7d9169ccfe5a7841c08b2799e4981066cb47968daaf26b
6
+ metadata.gz: 553fe2590a1803cf52b166290b6c2d2525f58d59a45bba5f1b2f1e1a8e6be42451f5e6642c1971195816bdbe8a3573f5327f5b1f9fedf46abe57762bc1131fd4
7
+ data.tar.gz: 1ded83dc81de148793c4e98ad809e31efff083b650cd69af07b99e305f0ada3e1a4ccc749a00569838397d018ff1817d40a8a2e89a7ae0964cc8ea4afe4f8ef6
@@ -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
- self.instance_variable_set(:@defined_uniques, nil)
83
- self.instance_variable_set(:@valid_uniques, nil)
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
- data = if data.length <= 4096 && data.split('\n').length == 1
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
- # Hope that other multi-line strings might be CSV data
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 before_import ||= (import_template[:before_import]) # || some generic before_import)
147
- before_import.call(data)
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
- # %%% This should be more general than just for self-referencing things.
296
- sub_cols = cols.map { |c| c.start_with?(trim_prefix) ? c[trim_prefix.length..-1] : nil }
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 nil anymore?
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
- # binding.pry if sub_obj.reports_to
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 'true', 't', 'on'
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 'false', 'f', 'off'
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
- if @after_import ||= (import_template[:after_import]) # || some generic after_import)
429
- ret = ret2 if (ret2 = @after_import.call(ret)).is_a?(Hash)
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, row = nil, obj = nil, all = nil, trim_prefix = '')
439
- col_name_offset = trim_prefix.length
440
- @valid_uniques ||= {} # Fancy memoisation
441
- col_list = cols.join('|')
442
- unless (vus = @valid_uniques[col_list])
443
- # Find all unique combinations that are available based on incoming columns, and
444
- # pair them up with column number mappings.
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
- # %%% If uniqueness is based on something else hanging out on a belongs_to then we're pretty hosed.
481
- # (Case in point, importing Order with related Order Detail and Product, and then Product needs to
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
- ret[sn_assoc.foreign_key] = nil if only_valid_uniques
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
- unless sn_bt.options[:optional] || !sn_bt.klass.belongs_to_required_by_default
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
- if train_we_came_in_here_on != false
542
- criteria = ret.each_with_object({}) do |v, s|
543
- next if bt_col_indexes.include?(v.last)
541
+ unless only_valid_uniques
542
+ uniq_lookups.each do |k, v|
543
+ next if bt_col_indexes.include?(v)
544
544
 
545
- new_criteria_all_nil = false if (s[v.first.to_sym] = row[v.last])
546
- s
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 ret.merge(criteria) if only_valid_uniques
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
- sub_hm = obj.find do |hm_obj|
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 hm_obj.send(k).to_s != v.to_s
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
- # Try looking it up through ActiveRecord
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
- (starred - utilised.keys).each { |star| defined_uniq[[star]] = [cols.index(star)] }
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
- puts "* In the #{klass.name} model \"validates_presence_of :#{attrib}\" should be removed as it does not refer to any existing column."
244
- errored_columns << klass_col
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
@@ -5,7 +5,7 @@ module DutyFree
5
5
  module VERSION
6
6
  MAJOR = 1
7
7
  MINOR = 0
8
- TINY = 3
8
+ TINY = 4
9
9
 
10
10
  # PRE is nil unless it's a pre-release (beta, RC, etc.)
11
11
  PRE = nil
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.3
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-06 00:00:00.000000000 Z
11
+ date: 2020-11-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord