brick 1.0.49 → 1.0.52

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8b42f1ad45e6dc942ed2e875d39318f8705f9a467c0cb31f267a71a01053bfd4
4
- data.tar.gz: 1e8f0cd1c374c5d75be4e4f1a8b659dd32b46f991c85cce4d234a6949d017e4b
3
+ metadata.gz: e3d0b398d1d3926fa3e59281c976fe2f7a54bfc16de4f99683928ce71d7ace97
4
+ data.tar.gz: 344c0de3e8691583e9a940ee451ad29015d46b0cbc55756d3b36e10d9ce27edb
5
5
  SHA512:
6
- metadata.gz: 437d415278f01a2ffced31687f77324c21416e6e7ef395d6a5d3db5a1853ccfb301c01716747ba4427417164a1200100205e7b7c75443bef83f1050f01683dda
7
- data.tar.gz: d42367f291f2900876c5263aab30280f7b5b3d9f205c4199349b9e24d35326b5457e1db8fd0d39a512f59af9691bbe44e29dd05d3384d5a0013c05ffe6447d8c
6
+ metadata.gz: e0cff4e30c30d33dd13bd5a6a4a888d52e0552fc692369c42a53846da00e9ce677ab48ba840ef1396728d339984e5f7ff35d9ce33ea60f8421b9fa19edc14575
7
+ data.tar.gz: 5971fcc802dd1732f71d3bcd015e4b616f7775028a10205c7e4b9b1fa41d13c0318f581c966c223e9a0661b8b9fa52e1197ae78c007144e93ec96de61b084663
@@ -221,13 +221,19 @@ module ActiveRecord
221
221
  template
222
222
  end
223
223
 
224
- # belongs_to DSL descriptions
225
- def self._br_bt_descrip
226
- @_br_bt_descrip ||= {}
227
- end
228
- # has_many count definitions
229
- def self._br_hm_counts
230
- @_br_hm_counts ||= {}
224
+ class << self
225
+ # belongs_to DSL descriptions
226
+ def _br_bt_descrip
227
+ @_br_bt_descrip ||= {}
228
+ end
229
+ # has_many count definitions
230
+ def _br_hm_counts
231
+ @_br_hm_counts ||= {}
232
+ end
233
+ # has_many :through associative tables
234
+ def _br_associatives
235
+ @_br_associatives ||= {}
236
+ end
231
237
  end
232
238
 
233
239
  # Search for BT, HM, and HMT DSL stuff
@@ -374,7 +380,7 @@ module ActiveRecord
374
380
 
375
381
  case (ks = k.split('.')).length
376
382
  when 1
377
- next unless klass._brick_get_fks.include?(k)
383
+ next unless klass.column_names.any?(k) || klass._brick_get_fks.include?(k)
378
384
  when 2
379
385
  assoc_name = ks.first.to_sym
380
386
  # Make sure it's a good association name and that the model has that column name
@@ -408,6 +414,7 @@ module ActiveRecord
408
414
  chains = rel_dupe._brick_chains
409
415
  id_for_tables = Hash.new { |h, k| h[k] = [] }
410
416
  field_tbl_names = Hash.new { |h, k| h[k] = {} }
417
+ used_col_aliases = {} # Used to make sure there is not a name clash
411
418
  bt_columns = klass._br_bt_descrip.each_with_object([]) do |v, s|
412
419
  v.last.each do |k1, v1| # k1 is class, v1 is array of columns to snag
413
420
  next if chains[k1].nil?
@@ -419,7 +426,12 @@ module ActiveRecord
419
426
 
420
427
  # Postgres can not use DISTINCT with any columns that are XML, so for any of those just convert to text
421
428
  is_xml = is_distinct && Brick.relations[sel_col.first.table_name]&.[](:cols)&.[](sel_col.last)&.first&.start_with?('xml')
422
- selects << "\"#{field_tbl_name}\".\"#{sel_col.last}\"#{'::text' if is_xml} AS \"#{(col_alias = "_brfk_#{v.first}__#{sel_col.last}")}\""
429
+ # If it's not unique then also include the belongs_to association name before the column name
430
+ if used_col_aliases.key?(col_alias = "_brfk_#{v.first}__#{sel_col.last}")
431
+ col_alias = "_brfk_#{v.first}__#{v1[idx][-2..-1].map(&:to_s).join('__')}"
432
+ end
433
+ selects << "\"#{field_tbl_name}\".\"#{sel_col.last}\"#{'::text' if is_xml} AS \"#{col_alias}\""
434
+ used_col_aliases[col_alias] = nil
423
435
  v1[idx] << col_alias
424
436
  end
425
437
 
@@ -447,8 +459,7 @@ module ActiveRecord
447
459
  klass._br_hm_counts.each do |k, hm|
448
460
  associative = nil
449
461
  count_column = if hm.options[:through]
450
- fk_col = (associative = associatives[hm.name])&.foreign_key
451
- hm.foreign_key if fk_col
462
+ hm.foreign_key if (fk_col = (associative = klass._br_associatives&.[](hm.name))&.foreign_key)
452
463
  else
453
464
  fk_col = hm.foreign_key
454
465
  poly_type = hm.inverse_of.foreign_type if hm.options.key?(:as)
@@ -502,7 +513,7 @@ JOIN (SELECT #{selects.join(', ')}, COUNT(#{'DISTINCT ' if hm.options[:through]}
502
513
  end
503
514
 
504
515
  private
505
-
516
+
506
517
  def shift_or_first(ary)
507
518
  ary.length > 1 ? ary.shift : ary.first
508
519
  end
@@ -536,12 +547,23 @@ JOIN (SELECT #{selects.join(', ')}, COUNT(#{'DISTINCT ' if hm.options[:through]}
536
547
  this_module.const_set(module_name.to_sym, Module.new)
537
548
  end
538
549
  end
539
- if this_module.const_defined?(class_name = module_prefixes.last.to_sym)
540
- this_module.const_get(class_name)
541
- else
542
- # Build STI subclass and place it into the namespace module
543
- this_module.const_set(class_name, klass = Class.new(self))
544
- klass
550
+ begin
551
+ if this_module.const_defined?(class_name = module_prefixes.last.to_sym)
552
+ this_module.const_get(class_name)
553
+ else
554
+ # Build STI subclass and place it into the namespace module
555
+ this_module.const_set(class_name, klass = Class.new(self))
556
+ klass
557
+ end
558
+ rescue NameError => err
559
+ if column_names.include?(inheritance_column)
560
+ puts "Table #{table_name} has column #{inheritance_column} which ActiveRecord expects to use as its special inheritance column."
561
+ puts "Unfortunately the value \"#{type_name}\" does not seem to refer to a valid type name, greatly confusing matters. If that column is intended to be used for data and not STI, consider putting this line into your Brick initializer so that only for this table that column will not clash with ActiveRecord:"
562
+ puts " Brick.sti_type_column = { 'rails_#{inheritance_column}' => ['#{table_name}'] }"
563
+ self
564
+ else
565
+ raise
566
+ end
545
567
  end
546
568
  end
547
569
  end
@@ -592,6 +614,8 @@ Module.class_exec do
592
614
  return possible
593
615
  end
594
616
  class_name = args.first.to_s
617
+ # self.name is nil when a model name is requested in an .erb file
618
+ base_module = (self < ActiveRecord::Migration || !self.name) ? Object : self
595
619
  # See if a file is there in the same way that ActiveSupport::Dependencies#load_missing_constant
596
620
  # checks for it in ~/.rvm/gems/ruby-2.7.5/gems/activesupport-5.2.6.2/lib/active_support/dependencies.rb
597
621
  # that is, checking #qualified_name_for with: from_mod, const_name
@@ -599,14 +623,17 @@ Module.class_exec do
599
623
  # path_suffix = ActiveSupport::Dependencies.qualified_name_for(Object, args.first).underscore
600
624
  # return self._brick_const_missing(*args) if ActiveSupport::Dependencies.search_for_file(path_suffix)
601
625
  # If the file really exists, go and snag it:
602
- if !(is_found = ActiveSupport::Dependencies.search_for_file(class_name.underscore)) && (filepath = (self.name || class_name)&.split('::'))
603
- filepath = (filepath[0..-2] + [class_name]).join('/').underscore + '.rb'
604
- end
605
- if is_found
606
- return self._brick_const_missing(*args)
607
- # elsif ActiveSupport::Dependencies.search_for_file(filepath) # Last-ditch effort to pick this thing up before we fill in the gaps on our own
608
- # my_const = parent.const_missing(class_name) # ends up having: MyModule::MyClass
609
- # return my_const
626
+ if ActiveSupport::Dependencies.search_for_file(class_name.underscore)
627
+ return base_module._brick_const_missing(*args)
628
+ # elsif ActiveSupport::Dependencies.search_for_file(filepath) # Last-ditch effort to pick this thing up before we fill in the gaps on our own
629
+ # my_const = parent.const_missing(class_name) # ends up having: MyModule::MyClass
630
+ # return my_const
631
+ else
632
+ filepath = base_module.name&.split('::')&.[](0..-2) unless base_module == Object
633
+ filepath = ((filepath || []) + [class_name]).join('/').underscore + '.rb'
634
+ if ActiveSupport::Dependencies.search_for_file(filepath) # Last-ditch effort to pick this thing up before we fill in the gaps on our own
635
+ return base_module._brick_const_missing(*args)
636
+ end
610
637
  end
611
638
 
612
639
  relations = ::Brick.relations
@@ -625,7 +652,7 @@ Module.class_exec do
625
652
  Object.send(:build_controller, self, class_name, plural_class_name, model, relations)
626
653
  end
627
654
  elsif (::Brick.enable_models? || ::Brick.enable_controllers?) && # Schema match?
628
- self == Object && # %%% This works for Person::Person -- but also limits us to not being able to allow more than one level of namespacing
655
+ base_module == Object && # %%% This works for Person::Person -- but also limits us to not being able to allow more than one level of namespacing
629
656
  (schema_name = [(singular_table_name = class_name.underscore),
630
657
  (table_name = singular_table_name.pluralize),
631
658
  class_name,
@@ -633,7 +660,7 @@ Module.class_exec do
633
660
  (::Brick.config.sti_namespace_prefixes&.key?("::#{class_name}::") && class_name))
634
661
  # Build out a module for the schema if it's namespaced
635
662
  # schema_name = schema_name.camelize
636
- self.const_set(schema_name.to_sym, (built_module = Module.new))
663
+ base_module.const_set(schema_name.to_sym, (built_module = Module.new))
637
664
 
638
665
  [built_module, "module #{schema_name}; end\n"]
639
666
  # # %%% Perhaps an option to use the first module just as schema, and additional modules as namespace with a table name prefix applied
@@ -643,8 +670,8 @@ Module.class_exec do
643
670
  # See if a file is there in the same way that ActiveSupport::Dependencies#load_missing_constant
644
671
  # checks for it in ~/.rvm/gems/ruby-2.7.5/gems/activesupport-5.2.6.2/lib/active_support/dependencies.rb
645
672
 
646
- if (base_model = ::Brick.config.sti_namespace_prefixes&.fetch("::#{self.name}::", nil)&.constantize) || # Are we part of an auto-STI namespace? ...
647
- self != Object # ... or otherwise already in some namespace?
673
+ if (base_model = ::Brick.config.sti_namespace_prefixes&.fetch("::#{base_module.name}::", nil)&.constantize) || # Are we part of an auto-STI namespace? ...
674
+ base_module != Object # ... or otherwise already in some namespace?
648
675
  schema_name = [(singular_schema_name = name.underscore),
649
676
  (schema_name = singular_schema_name.pluralize),
650
677
  name,
@@ -657,7 +684,7 @@ Module.class_exec do
657
684
  if base_model
658
685
  schema_name = name.underscore # For the auto-STI namespace models
659
686
  table_name = base_model.table_name
660
- Object.send(:build_model, self, inheritable_name, model_name, singular_table_name, table_name, relations, table_name)
687
+ Object.send(:build_model, base_module, inheritable_name, model_name, singular_table_name, table_name, relations, table_name)
661
688
  else
662
689
  # Adjust for STI if we know of a base model for the requested model name
663
690
  # %%% Does not yet work with namespaced model names. Perhaps prefix with plural_class_name when doing the lookups here.
@@ -682,15 +709,15 @@ Module.class_exec do
682
709
  built_class
683
710
  elsif ::Brick.config.sti_namespace_prefixes&.key?("::#{class_name}") && !schema_name
684
711
  # module_prefixes = type_name.split('::')
685
- # path = self.name.split('::')[0..-2] + []
712
+ # path = base_module.name.split('::')[0..-2] + []
686
713
  # module_prefixes.unshift('') unless module_prefixes.first.blank?
687
714
  # candidate_file = Rails.root.join('app/models' + module_prefixes.map(&:underscore).join('/') + '.rb')
688
- self._brick_const_missing(*args)
689
- # elsif self != Object
715
+ base_module._brick_const_missing(*args)
716
+ # elsif base_module != Object
690
717
  # module_parent.const_missing(*args)
691
718
  else
692
- puts "MISSING! #{self.name} #{args.inspect} #{table_name}"
693
- self._brick_const_missing(*args)
719
+ puts "MISSING! #{base_module.name} #{args.inspect} #{table_name}"
720
+ base_module._brick_const_missing(*args)
694
721
  end
695
722
  end
696
723
  end
@@ -831,15 +858,15 @@ class Object
831
858
  "#{hmt_fk}_through_#{hm.first[:assoc_name]}"
832
859
  else # Use BT names to provide uniqueness
833
860
  if self.name.underscore.singularize == hm.first[:alternate_name]
834
- # Has previously been:
835
- # # If it folds back on itself then look at the other side
836
- # # (At this point just infer the source be the inverse of the first has_many that
837
- # # we find that is not ourselves. If there are more than two then uh oh, can't
838
- # # yet handle that rare circumstance!)
839
- # other = hms.find { |hm1| hm1 != hm } # .first[:fk]
840
- # options[:source] = other.first[:inverse][:assoc_name].to_sym
841
- # And also has been:
842
- # hm.first[:inverse][:assoc_name].to_sym
861
+ # Has previously been:
862
+ # # If it folds back on itself then look at the other side
863
+ # # (At this point just infer the source be the inverse of the first has_many that
864
+ # # we find that is not ourselves. If there are more than two then uh oh, can't
865
+ # # yet handle that rare circumstance!)
866
+ # other = hms.find { |hm1| hm1 != hm } # .first[:fk]
867
+ # options[:source] = other.first[:inverse][:assoc_name].to_sym
868
+ # And also has been:
869
+ # hm.first[:inverse][:assoc_name].to_sym
843
870
  options[:source] = hm.last.to_sym
844
871
  else
845
872
  through = hm.first[:alternate_name].pluralize
@@ -1097,9 +1124,7 @@ class Object
1097
1124
  is_pk_string = nil
1098
1125
  if (pk_col = model&.primary_key)
1099
1126
  code << " def show\n"
1100
- code << (find_by_id = " id = params[:id]&.split(/[\\/,_]/)
1101
- id = id.first if id.is_a?(Array) && id.length == 1
1102
- @#{singular_table_name} = #{model.name}.find(id)\n")
1127
+ code << " #{find_by_name = "find_#{singular_table_name}"}\n"
1103
1128
  code << " end\n"
1104
1129
  self.define_method :show do
1105
1130
  ::Brick.set_db_schema(params)
@@ -1110,25 +1135,47 @@ class Object
1110
1135
  params[:id]&.split(/[\/,_]/)
1111
1136
  end
1112
1137
  id = id.first if id.is_a?(Array) && id.length == 1
1113
- instance_variable_set("@#{singular_table_name}".to_sym, model.find(id))
1138
+ instance_variable_set("@#{singular_table_name}".to_sym, find_obj)
1114
1139
  end
1115
1140
  end
1116
1141
 
1117
1142
  # By default, views get marked as read-only
1118
- unless is_swagger # model.readonly # (relation = relations[model.table_name]).key?(:isView)
1119
- code << " # (Define :new, :create)\n"
1143
+ # unless model.readonly # (relation = relations[model.table_name]).key?(:isView)
1144
+ code << " def new\n"
1145
+ code << " @#{singular_table_name} = #{model.name}.new\n"
1146
+ code << " end\n"
1147
+ self.define_method :new do
1148
+ ::Brick.set_db_schema(params)
1149
+ instance_variable_set("@#{singular_table_name}".to_sym, model.new)
1150
+ end
1151
+
1152
+ params_name_sym = (params_name = "#{singular_table_name}_params").to_sym
1120
1153
 
1121
- if model.primary_key
1154
+ code << " def create\n"
1155
+ code << " @#{singular_table_name} = #{model.name}.create(#{params_name})\n"
1156
+ code << " end\n"
1157
+ self.define_method :create do
1158
+ ::Brick.set_db_schema(params)
1159
+ instance_variable_set("@#{singular_table_name}".to_sym,
1160
+ model.send(:create, send(params_name_sym)))
1161
+ end
1162
+
1163
+ if pk_col
1122
1164
  # if (schema = ::Brick.config.schema_behavior[:multitenant]&.fetch(:schema_to_analyse, nil)) && ::Brick.db_schemas&.include?(schema)
1123
1165
  # ActiveRecord::Base.execute_sql("SET SEARCH_PATH = ?;", schema)
1124
1166
  # end
1125
1167
 
1126
1168
  is_need_params = true
1127
- # code << " # (Define :edit, and :destroy)\n"
1169
+ code << " def edit\n"
1170
+ code << " #{find_by_name}\n"
1171
+ code << " end\n"
1172
+ self.define_method :edit do
1173
+ ::Brick.set_db_schema(params)
1174
+ instance_variable_set("@#{singular_table_name}".to_sym, find_obj)
1175
+ end
1176
+
1128
1177
  code << " def update\n"
1129
- code << find_by_id
1130
- params_name = "#{singular_table_name}_params"
1131
- code << " @#{singular_table_name}.update(#{params_name})\n"
1178
+ code << " #{find_by_name}.update(#{params_name})\n"
1132
1179
  code << " end\n"
1133
1180
  self.define_method :update do
1134
1181
  ::Brick.set_db_schema(params)
@@ -1147,27 +1194,50 @@ class Object
1147
1194
  # return
1148
1195
  end
1149
1196
 
1197
+ instance_variable_set("@#{singular_table_name}".to_sym, (obj = find_obj))
1198
+ obj.send(:update, send(params_name_sym))
1199
+ end
1200
+
1201
+ code << " def destroy\n"
1202
+ code << " #{find_by_name}.destroy\n"
1203
+ code << " end\n"
1204
+ self.define_method :destroy do
1205
+ ::Brick.set_db_schema(params)
1206
+ instance_variable_set("@#{singular_table_name}".to_sym, find_obj.send(:destroy))
1207
+ end
1208
+ end
1209
+
1210
+ code << "private\n" if pk_col || is_need_params
1211
+
1212
+ if pk_col
1213
+ code << " def find_#{singular_table_name}
1214
+ id = params[:id]&.split(/[\\/,_]/)
1215
+ @#{singular_table_name} = #{model.name}.find(id.is_a?(Array) && id.length == 1 ? id.first : id)
1216
+ end\n"
1217
+ self.define_method :find_obj do
1150
1218
  id = is_pk_string ? params[:id] : params[:id]&.split(/[\/,_]/)
1151
- id = id.first if id.is_a?(Array) && id.length == 1
1152
- instance_variable_set("@#{singular_table_name}".to_sym, (obj = model.find(id)))
1153
- obj = obj.first if obj.is_a?(Array)
1154
- obj.send(:update, send(params_name = params_name.to_sym))
1219
+ model.find(id.is_a?(Array) && id.length == 1 ? id.first : id)
1155
1220
  end
1156
1221
  end
1157
1222
 
1158
1223
  if is_need_params
1159
- code << "private\n"
1160
1224
  code << " def #{params_name}\n"
1225
+ permits = model.columns_hash.keys.map(&:to_sym)
1226
+ permits_txt = permits.map(&:inspect) +
1227
+ model.reflect_on_all_associations.select { |assoc| assoc.macro == :has_many && assoc.options[:through] }.map do |assoc|
1228
+ permits << { "#{assoc.name.to_s.singularize}_ids".to_sym => [] }
1229
+ "#{assoc.name.to_s.singularize}_ids: []"
1230
+ end
1161
1231
  code << " params.require(:#{require_name = model.name.underscore.tr('/', '_')
1162
- }).permit(#{model.columns_hash.keys.map { |c| c.to_sym.inspect }.join(', ')})\n"
1232
+ }).permit(#{permits_txt.join(', ')})\n"
1163
1233
  code << " end\n"
1164
1234
  self.define_method(params_name) do
1165
- params.require(require_name.to_sym).permit(model.columns_hash.keys)
1235
+ params.require(require_name.to_sym).permit(permits)
1166
1236
  end
1167
1237
  private params_name
1168
1238
  # Get column names for params from relations[model.table_name][:cols].keys
1169
1239
  end
1170
- end
1240
+ # end
1171
1241
  code << "end # #{namespace_name}#{class_name}\n\n"
1172
1242
  end # class definition
1173
1243
  [built_controller, code]
@@ -58,7 +58,9 @@ module Brick
58
58
  def template_exists?(*args, **options)
59
59
  (::Brick.config.add_orphans && args.first == 'orphans') ||
60
60
  _brick_template_exists?(*args, **options) ||
61
- set_brick_model(args)
61
+ # Do not auto-create a template when it's searching for an application.html.erb, which comes in like: ["edit", ["games", "application"]]
62
+ ((args[1].length == 1 || args[1][-1] != 'application') &&
63
+ set_brick_model(args))
62
64
  end
63
65
 
64
66
  def set_brick_model(find_args)
@@ -104,7 +106,7 @@ module Brick
104
106
  path_obj_name = model_name.underscore.tr('/', '_')
105
107
  table_name = obj_name.pluralize
106
108
  template_link = nil
107
- bts, hms, associatives = ::Brick.get_bts_and_hms(@_brick_model) # This gets BT and HM and also has_many :through (HMT)
109
+ bts, hms = ::Brick.get_bts_and_hms(@_brick_model) # This gets BT and HM and also has_many :through (HMT)
108
110
  hms_columns = [] # Used for 'index'
109
111
  skip_klass_hms = ::Brick.config.skip_index_hms[model_name] || {}
110
112
  hms_headers = hms.each_with_object([]) do |hm, s|
@@ -112,7 +114,7 @@ module Brick
112
114
  "H#{hm_assoc.macro == :has_one ? 'O' : 'M'}#{'T' if hm_assoc.options[:through]}",
113
115
  (assoc_name = hm.first)]
114
116
  hm_fk_name = if hm_assoc.options[:through]
115
- associative = associatives[hm.first]
117
+ associative = @_brick_model._br_associatives[hm.first]
116
118
  tbl_nm = if hm_assoc.options[:source]
117
119
  associative.klass.reflect_on_association(hm_assoc.options[:source]).inverse_of&.name
118
120
  else
@@ -131,25 +133,21 @@ module Brick
131
133
  case args.first
132
134
  when 'index'
133
135
  hms_columns << if hm_assoc.macro == :has_many
134
- set_ct = if skip_klass_hms.key?(assoc_name.to_sym)
135
- 'nil'
136
- else
137
- # Postgres column names are limited to 63 characters
138
- attrib_name = "_br_#{assoc_name}_ct"[0..62]
139
- "#{obj_name}.#{attrib_name} || 0"
140
- end
141
136
  if hm_fk_name
142
- "<%= ct = #{set_ct}
143
- link_to \"#\{ct || 'View'\} #{assoc_name}\", #{hm_assoc.klass.name.underscore.tr('/', '_').pluralize}_path({ #{path_keys(hm_assoc, hm_fk_name, obj_name, pk)} }) unless ct&.zero? %>\n"
137
+ set_ct = if skip_klass_hms.key?(assoc_name.to_sym)
138
+ 'nil'
139
+ else
140
+ # Postgres column names are limited to 63 characters
141
+ attrib_name = "_br_#{assoc_name}_ct"[0..62]
142
+ "#{obj_name}.#{attrib_name} || 0"
143
+ end
144
+ "#{hm_assoc.name}: [#{assoc_name.inspect}, #{set_ct}, #{path_keys(hm_assoc, hm_fk_name, obj_name, pk)}]"
144
145
  else # %%% Would be able to remove this when multiple foreign keys to same destination becomes bulletproof
145
- "#{assoc_name}\n"
146
+ "#{hm_assoc.name}: [#{assoc_name.inspect}]"
146
147
  end
147
148
  else # has_one
148
149
  # 0..62 because Postgres column names are limited to 63 characters
149
- "<%= descrips = @_brick_bt_descrip[#{hm.first.inspect}][ho_class = #{hm[1].klass.name}]
150
- ho_txt = ho_class.brick_descrip(#{obj_name}, descrips[0..-2].map { |id| #{obj_name}.send(id.last[0..62]) }, (ho_id_col = descrips.last))
151
- ho_id = ho_id_col.map { |id_col| #{obj_name}.send(id_col.to_sym) }
152
- ho_id&.first ? link_to(ho_txt, send(\"#\{ho_class.base_class.name.underscore.tr('/', '_')\}_path\".to_sym, ho_id)) : ho_txt %>\n"
150
+ "#{hm_assoc.name}: [#{assoc_name.inspect}, nil, #{path_keys(hm_assoc, hm_fk_name, obj_name, pk)}]"
153
151
  end
154
152
  when 'show', 'update'
155
153
  hm_stuff << if hm_fk_name
@@ -166,12 +164,12 @@ module Brick
166
164
  # %%% If we are not auto-creating controllers (or routes) then omit by default, and if enabled anyway, such as in a development
167
165
  # environment or whatever, then get either the controllers or routes list instead
168
166
  apartment_default_schema = ::Brick.apartment_multitenant && Apartment.default_schema
169
- table_options = (::Brick.relations.keys - ::Brick.config.exclude_tables).map do |tbl|
167
+ table_options = (::Brick.relations.keys - ::Brick.config.exclude_tables).each_with_object({}) do |tbl, s|
170
168
  if (tbl_parts = tbl.split('.')).first == apartment_default_schema
171
169
  tbl = tbl_parts.last
172
170
  end
173
- tbl
174
- end.sort.each_with_object(+'') do |v, s|
171
+ s[tbl] = nil
172
+ end.keys.sort.each_with_object(+'') do |v, s|
175
173
  s << "<option value=\"#{v.underscore.gsub('.', '/').pluralize}\">#{v}</option>"
176
174
  end.html_safe
177
175
  table_options << '<option value="brick_orphans">(Orphans)</option>'.html_safe if is_orphans
@@ -283,8 +281,8 @@ input+svg.revert {
283
281
  color: #FFF;
284
282
  }
285
283
  </style>
286
- <% is_includes_dates = nil
287
284
 
285
+ <% is_includes_dates = nil
288
286
  def is_bcrypt?(val)
289
287
  val.is_a?(String) && val.length == 60 && val.start_with?('$2a$')
290
288
  end
@@ -553,46 +551,46 @@ if (headerTop) {
553
551
  <br>
554
552
  <table id=\"headerTop\">
555
553
  <table id=\"#{table_name}\">
556
- <thead><tr>#{"<th x-order=\"#{pk.join(',')}\"></th>" if pk.present?}<%
554
+ <thead><tr>#{"<th x-order=\"#{pk.join(',')}\"></th>" if pk.present?}<%=
557
555
  col_order = []
558
- @#{table_name}.columns.each do |col|
559
- next if (#{(pk || []).inspect}.include?(col_name = col.name) && col.type == :integer && !bts.key?(col_name)) ||
560
- ::Brick.config.metadata_columns.include?(col_name) || poly_cols.include?(col_name)
561
-
562
- col_order << col_name
563
- %><th<%= \" title=\\\"#\{col.comment}\\\"\".html_safe if col.respond_to?(:comment) && !col.comment.blank? %><%
564
- if (bt = bts[col_name]) %>
565
- <%= \" x-order=\\\"#\{bt.first}\\\"\".html_safe if true # Currently we always allow click to sort
566
- %>>BT <%
567
- bt[1].each do |bt_pair| %><%=
568
- bt_pair.first.bt_link(bt.first) %> <%
569
- end %><%
570
- else %><%= \" x-order=\\\"#\{col_name}\\\"\".html_safe if true # Currently we always allow click to sort
571
- %>><%= col_name %><%
572
- end
573
- %></th><%
574
- end
575
556
  # Consider getting the name from the association -- h.first.name -- if a more \"friendly\" alias should be used for a screwy table name
576
- %>#{hms_headers.map do |h|
577
- # Currently we always allow click to sort
578
- "<th#{" x-order=\"#{h.first.name}\"" if true}>" +
579
- if h.first.options[:through] && !h.first.through_reflection
580
- "#{h[1]} #{h[2]} %></th>" # %%% Would be able to remove this when multiple foreign keys to same destination becomes bulletproof
581
- else
582
- "#{h[1]} <%= link_to('#{h[2]}', #{h.first.klass.name.underscore.tr('/', '_').pluralize}_path) %></th>"
583
- end
584
- end.join
585
- }</tr></thead>
586
-
557
+ hms_hdrs = {#{hms_headers.map do |hm|
558
+ "#{hm.first.name}: [#{hm.first.name.inspect}, #{(hm.first.options[:through] && !hm.first.through_reflection).inspect}, #{hm.first.klass.name}, #{hm[1].inspect}, #{hm[2].inspect}]"
559
+ end.join(', ')}}
560
+ (@#{table_name}.columns + hms_hdrs.values).each_with_object(+'') do |col, s|
561
+ if col.is_a?(ActiveRecord::ConnectionAdapters::Column)
562
+ next if (#{(pk || []).inspect}.include?(col_name = col.name) && col.type == :integer && !bts.key?(col_name)) ||
563
+ ::Brick.config.metadata_columns.include?(col_name) || poly_cols.include?(col_name)
564
+
565
+ col_order << col_name
566
+ s << if (bt = bts[col_name])
567
+ \"<th#\{' x-order=\"' + bt.first.to_s + '\"' unless bt[2]}>BT \" + # Allow sorting any BT except polymorphics
568
+ bt[1].map { |bt_pair| bt_pair.first.bt_link(bt.first) }.join(' ')
569
+ else
570
+ # Currently we always allow click to sort on non-BT columns
571
+ \"<th#\{' x-order=\"' + col_name + '\"' if true}>#\{col_name}\"
572
+ end + '</th>'
573
+ else # Currently we always allow click to sort on all HM columns (col is the hm array)
574
+ col_order << col.first # hm.name
575
+ s << \"<th#\{' x-order=\"' + col.first.to_s + '\"' if true}>\"
576
+ s << if col[1]
577
+ \"#\{col[3]} #\{col[4]}\" # %%% Would be able to remove this when multiple foreign keys to same destination becomes bulletproof
578
+ else
579
+ \"#\{col[3]} #\{link_to(col[4], send(\"#\{col[2].name.underscore.tr('/', '_').pluralize}_path\"))}\"
580
+ end + '</th>'
581
+ end
582
+ end.html_safe
583
+ %></tr></thead>
587
584
  <tbody>
588
- <% @#{table_name}.each do |#{obj_name}| %>
585
+ <% @#{table_name}.each do |#{obj_name}|
586
+ hms_cols = {#{hms_columns.join(', ')}} %>
589
587
  <tr>#{"
590
588
  <td><%= link_to '⇛', #{path_obj_name}_path(#{obj_pk}), { class: 'big-arrow' } %></td>" if obj_pk}
591
589
  <% col_order.each do |col_name|
592
590
  val = #{obj_name}.attributes[col_name] %>
593
- <td>
594
- <% if (bt = bts[col_name]) %>
595
- <% if bt[2] # Polymorphic?
591
+ <td><%
592
+ if (bt = bts[col_name])
593
+ if bt[2] # Polymorphic?
596
594
  bt_class = #{obj_name}.send(\"#\{bt.first\}_type\")
597
595
  base_class = (::Brick.existing_stis[bt_class] || bt_class).constantize.base_class.name.underscore
598
596
  poly_id = #{obj_name}.send(\"#\{bt.first\}_id\")
@@ -608,12 +606,26 @@ if (headerTop) {
608
606
  <%= bt_id&.first ? link_to(bt_txt, send(\"#\{bt_class.base_class.name.underscore.tr('/', '_')\}_path\".to_sym, bt_id)) : bt_txt %>
609
607
  <%#= Previously was: bt_obj = bt[1].first.first.find_by(bt[2] => val); link_to(bt_obj.brick_descrip, send(\"#\{bt[1].first.first.name.underscore\}_path\".to_sym, bt_obj.send(bt[1].first.first.primary_key.to_sym))) if bt_obj %>
610
608
  <% end %>
611
- <% else %>
612
- <%= hide_bcrypt(val) %>
613
- <% end %>
614
- </td>
609
+ <% elsif (hms_col = hms_cols[col_name])
610
+ if hms_col.length == 1 %>
611
+ <%= hms_col.first %>
612
+ <% else
613
+ klass = (col = hms_hdrs[col_name])[2]
614
+ txt = if col[3] == 'HO'
615
+ descrips = @_brick_bt_descrip[col_name][klass]
616
+ ho_txt = klass.brick_descrip(#{obj_name}, descrips[0..-2].map { |id| #{obj_name}.send(id.last[0..62]) }, (ho_id_col = descrips.last))
617
+ ho_id = ho_id_col.map { |id_col| #{obj_name}.send(id_col.to_sym) }
618
+ ho_id&.first ? link_to(ho_txt, send(\"#\{klass.base_class.name.underscore.tr('/', '_')\}_path\".to_sym, ho_id)) : ho_txt
619
+ else
620
+ \"#\{hms_col[1] || 'View'\} #\{hms_col.first}\"
621
+ end %>
622
+ <%= link_to txt, send(\"#\{klass.name.underscore.tr('/', '_').pluralize}_path\".to_sym, hms_col[2]) unless hms_col[1]&.zero? %>
623
+ <% end %>
624
+ <% else
625
+ %><%= hide_bcrypt(val) %><%
626
+ end
627
+ %></td>
615
628
  <% end %>
616
- #{hms_columns.each_with_object(+'') { |hm_col, s| s << "<td>#{hm_col}</td>" }}
617
629
  </tr>
618
630
  <% end %>
619
631
  </tbody>
@@ -807,7 +819,9 @@ flatpickr(\".timepicker\", {enableTime: true, noCalendar: true});
807
819
  # %%% Create a smart javascript routine which can do this client-side %>
808
820
  [... document.getElementsByTagName(\"TH\")].forEach(function (th) {
809
821
  th.addEventListener(\"click\", function (e) {
810
- location.href = changeout(location.href, \"_brick_order\", this.getAttribute(\"x-order\"));
822
+ var xOrder;
823
+ if (xOrder = this.getAttribute(\"x-order\"))
824
+ location.href = changeout(location.href, \"_brick_order\", xOrder);
811
825
  });
812
826
  });
813
827
  document.querySelectorAll(\"input, select\").forEach(function (inp) {
@@ -5,7 +5,7 @@ module Brick
5
5
  module VERSION
6
6
  MAJOR = 1
7
7
  MINOR = 0
8
- TINY = 49
8
+ TINY = 52
9
9
 
10
10
  # PRE is nil unless it's a pre-release (beta, RC, etc.)
11
11
  PRE = nil
data/lib/brick.rb CHANGED
@@ -172,14 +172,14 @@ module Brick
172
172
  # Mark has_manys that go to an associative ("join") table so that they are skipped in the UI,
173
173
  # as well as any possible polymorphic associations
174
174
  skip_hms = {}
175
- associatives = hms.each_with_object({}) do |hmt, s|
175
+ hms.each do |hmt|
176
176
  if (through = hmt.last.options[:through])
177
177
  skip_hms[through] = nil # if hms[through]
178
178
  # binding.pry if !hms[through]
179
179
  # End up with a hash of HMT names pointing to join-table associations
180
180
  # Last part was: hmt.last.name
181
181
  # Changed up because looking for: hms[:issue_issue_duplicates]
182
- s[hmt.first] = hms[through] # || hms["#{(opt = hmt.last.options)[:through].to_s.singularize}_#{opt[:source].to_s.pluralize}".to_sym]
182
+ model._br_associatives[hmt.first] = hms[through] # || hms["#{(opt = hmt.last.options)[:through].to_s.singularize}_#{opt[:source].to_s.pluralize}".to_sym]
183
183
  elsif hmt.last.inverse_of.nil?
184
184
  puts "SKIPPING #{hmt.last.name.inspect}"
185
185
  # %%% If we don't do this then below associative.name will find that associative is nil
@@ -187,7 +187,7 @@ module Brick
187
187
  end
188
188
  end
189
189
  skip_hms.each { |k, _v| hms.delete(k) }
190
- [bts, hms, associatives]
190
+ [bts, hms]
191
191
  end
192
192
 
193
193
  # Switches Brick auto-models on or off, for all threads
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: brick
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.49
4
+ version: 1.0.52
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lorin Thwaits
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-07-24 00:00:00.000000000 Z
11
+ date: 2022-08-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord