brick 1.0.33 → 1.0.36

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: 7bd78c8878b1ce8e8e58fb4d8463322269d2ac065c5ed12079dcc64360dc30d5
4
- data.tar.gz: e6926fdc0ec59ad609be39361dbfe0ccea24c1b08a01ccf0a4ae8eb1aa9e2ba2
3
+ metadata.gz: 6ef930474d4e1496812af0a626f57a2db1b05396c2dc46eb8f117c6fbf2f4df5
4
+ data.tar.gz: 8847971321e1a6178b340ef6929298d2d33edb1a1918584c43d67edc5b844a39
5
5
  SHA512:
6
- metadata.gz: 5b6ac439519209c3097c2b2651ed66f319b9c04072d2cee7262aad6c4d9907d61b5b45ee1812c1f6cea1e5e1eed2082eb15953e4e3097c9c12b4f35a1f3af703
7
- data.tar.gz: 5bb559ada7035abb062b0441578d5406e64f87b9f11fde1d5b3b880179098bafe9507a1a6cdd8e1af1cd1fb4defc1d339e0054896ca0e9c507ea831f24a0cb96
6
+ metadata.gz: cba480c932d00067c122b99d22f2633d8b26795295a4039a4c6ac014893ed0e4313ac33571cad06a880d9cbf426627e766c2b13514e7bf7b81093acc723aa425
7
+ data.tar.gz: 75aa1e29cd0619bf9654df74a4f36625b1b703bd307b9f72439e4ce9e25f0b80bd9fb10b4fe6f2eadf70effcf28849e1a513c1745d48b31000d33e8948ab555c
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_record/version'
4
+
5
+ # ActiveRecord before 4.0 didn't have #version
6
+ unless ActiveRecord.respond_to?(:version)
7
+ module ActiveRecord
8
+ def self.version
9
+ ::Gem::Version.new(ActiveRecord::VERSION::STRING)
10
+ end
11
+ end
12
+ end
13
+
14
+ # In ActiveSupport older than 5.0, the duplicable? test tries to new up a BigDecimal,
15
+ # and Ruby 2.6 and later deprecates #new. This removes the warning from BigDecimal.
16
+ # This compatibility needs to be put into place in the application's "config/boot.rb"
17
+ # file by having the line "require 'brick/compatibility'" to be the last line in that
18
+ # file.
19
+ require 'bigdecimal'
20
+ if ::Gem::Version.new(RUBY_VERSION) >= ::Gem::Version.new('2.6') &&
21
+ ActiveRecord.version < ::Gem::Version.new('5.0')
22
+ def BigDecimal.new(*args, **kwargs)
23
+ BigDecimal(*args, **kwargs)
24
+ end
25
+ end
@@ -163,6 +163,7 @@ module ActiveRecord
163
163
  bracket_name.split('.').each do |part|
164
164
  obj_name += ".#{part}"
165
165
  this_obj = caches.fetch(obj_name) { caches[obj_name] = this_obj&.send(part.to_sym) }
166
+ break if this_obj.nil?
166
167
  end
167
168
  this_obj&.to_s || ''
168
169
  end
@@ -202,7 +203,9 @@ module ActiveRecord
202
203
  model_underscore = name.underscore
203
204
  assoc_name = CGI.escapeHTML(assoc_name.to_s)
204
205
  model_path = Rails.application.routes.url_helpers.send("#{model_underscore.tr('/', '_').pluralize}_path".to_sym)
205
- link = Class.new.extend(ActionView::Helpers::UrlHelper).link_to(name, model_path)
206
+ av_class = Class.new.extend(ActionView::Helpers::UrlHelper)
207
+ av_class.extend(ActionView::Helpers::TagHelper) if ActionView.version < ::Gem::Version.new('6.1')
208
+ link = av_class.link_to(name, model_path)
206
209
  model_underscore == assoc_name ? link : "#{assoc_name}-#{link}".html_safe
207
210
  end
208
211
 
@@ -308,6 +311,23 @@ module ActiveRecord
308
311
  # , is_add_bts, is_add_hms
309
312
  )
310
313
  is_add_bts = is_add_hms = true
314
+ is_distinct = nil
315
+ wheres = {}
316
+ params.each do |k, v|
317
+ case (ks = k.split('.')).length
318
+ when 1
319
+ next unless klass._brick_get_fks.include?(k)
320
+ when 2
321
+ assoc_name = ks.first.to_sym
322
+ # Make sure it's a good association name and that the model has that column name
323
+ next unless klass.reflect_on_association(assoc_name)&.klass&.column_names&.any?(ks.last)
324
+
325
+ join_array[assoc_name] = nil # Store this relation name in our special collection for .joins()
326
+ is_distinct = true
327
+ distinct!
328
+ end
329
+ wheres[k] = v.split(',')
330
+ end
311
331
 
312
332
  # %%% Skip the metadata columns
313
333
  if selects&.empty? # Default to all columns
@@ -316,7 +336,9 @@ module ActiveRecord
316
336
  if (col_name = col.name) == 'class'
317
337
  col_alias = ' AS _class'
318
338
  end
319
- selects << "\"#{tbl_no_schema}\".\"#{col_name}\"#{col_alias}"
339
+ # Postgres can not use DISTINCT with any columns that are XML, so for any of those just convert to text
340
+ cast_as_text = '::text' if is_distinct && Brick.relations[klass.table_name]&.[](:cols)&.[](col.name)&.first&.start_with?('xml')
341
+ selects << "\"#{tbl_no_schema}\".\"#{col_name}\"#{cast_as_text}#{col_alias}"
320
342
  end
321
343
  end
322
344
 
@@ -342,22 +364,6 @@ module ActiveRecord
342
364
  end
343
365
  end
344
366
 
345
- wheres = {}
346
- params.each do |k, v|
347
- case (ks = k.split('.')).length
348
- when 1
349
- next unless klass._brick_get_fks.include?(k)
350
- when 2
351
- assoc_name = ks.first.to_sym
352
- # Make sure it's a good association name and that the model has that column name
353
- next unless klass.reflect_on_association(assoc_name)&.klass&.column_names&.any?(ks.last)
354
-
355
- join_array[assoc_name] = nil # Store this relation name in our special collection for .joins()
356
- distinct!
357
- end
358
- wheres[k] = v.split(',')
359
- end
360
-
361
367
  if join_array.present?
362
368
  left_outer_joins!(join_array)
363
369
  # Without working from a duplicate, touching the AREL ast tree sets the @arel instance variable, which causes the relation to be immutable.
@@ -375,7 +381,9 @@ module ActiveRecord
375
381
  v1.map { |x| [translations[x[0..-2].map(&:to_s).join('.')], x.last] }.each_with_index do |sel_col, idx|
376
382
  field_tbl_name = (field_tbl_names[v.first][sel_col.first] ||= shift_or_first(chains[sel_col.first])).split('.').last
377
383
 
378
- selects << "#{"\"#{field_tbl_name}\".\"#{sel_col.last}\""} AS \"#{(col_alias = "_brfk_#{v.first}__#{sel_col.last}")}\""
384
+ # Postgres can not use DISTINCT with any columns that are XML, so for any of those just convert to text
385
+ is_xml = is_distinct && Brick.relations[sel_col.first.table_name]&.[](:cols)&.[](sel_col.last)&.first&.start_with?('xml')
386
+ selects << "\"#{field_tbl_name}\".\"#{sel_col.last}\"#{'::text' if is_xml} AS \"#{(col_alias = "_brfk_#{v.first}__#{sel_col.last}")}\""
379
387
  v1[idx] << col_alias
380
388
  end
381
389
 
@@ -403,7 +411,6 @@ module ActiveRecord
403
411
  hm_counts.each do |k, hm|
404
412
  associative = nil
405
413
  count_column = if hm.options[:through]
406
- # binding.pry if associatives[hm.name].nil?
407
414
  fk_col = (associative = associatives[hm.name]).foreign_key
408
415
  hm.foreign_key
409
416
  else
@@ -494,8 +501,9 @@ if ActiveSupport::Dependencies.respond_to?(:autoload_module!) # %%% Only works w
494
501
  alias _brick_autoload_module! autoload_module!
495
502
  def autoload_module!(*args)
496
503
  into, const_name, qualified_name, path_suffix = args
497
- base_class_name = ::Brick.config.sti_namespace_prefixes&.fetch("::#{into.name}::", nil)
498
- base_class_name = "::#{base_class_name}" unless base_class_name.start_with?('::')
504
+ if (base_class_name = ::Brick.config.sti_namespace_prefixes&.fetch("::#{into.name}::", nil))
505
+ base_class_name = "::#{base_class_name}" unless base_class_name.start_with?('::')
506
+ end
499
507
  if (base_class = base_class_name&.constantize)
500
508
  ::Brick.sti_models[qualified_name] = { base: base_class }
501
509
  # Build subclass and place it into the specially STI-namespaced module
@@ -571,11 +579,13 @@ Module.class_exec do
571
579
  [built_module, "module #{schema_name}; end\n"]
572
580
  # # %%% Perhaps an option to use the first module just as schema, and additional modules as namespace with a table name prefix applied
573
581
  elsif ::Brick.enable_models?
582
+ # Custom inheritable Brick base model?
583
+ class_name = (inheritable_name = class_name)[5..-1] if class_name.start_with?('Brick')
574
584
  # See if a file is there in the same way that ActiveSupport::Dependencies#load_missing_constant
575
585
  # checks for it in ~/.rvm/gems/ruby-2.7.5/gems/activesupport-5.2.6.2/lib/active_support/dependencies.rb
576
586
 
577
- if self != Object || # Are we in some namespace? ...
578
- (base_model = ::Brick.config.sti_namespace_prefixes&.fetch("::#{name}::", nil)&.constantize) # ... or part of an auto-STI namespace?
587
+ if (base_model = ::Brick.config.sti_namespace_prefixes&.fetch("::#{name}::", nil)&.constantize) || # Are we part of an auto-STI namespace? ...
588
+ self != Object # ... or otherwise already in some namespace?
579
589
  schema_name = [(singular_schema_name = name.underscore),
580
590
  (schema_name = singular_schema_name.pluralize),
581
591
  name,
@@ -588,7 +598,7 @@ Module.class_exec do
588
598
  if base_model
589
599
  schema_name = name.underscore # For the auto-STI namespace models
590
600
  table_name = base_model.table_name
591
- Object.send(:build_model, self, model_name, singular_table_name, table_name, relations, table_name)
601
+ Object.send(:build_model, self, inheritable_name, model_name, singular_table_name, table_name, relations, table_name)
592
602
  else
593
603
  # Adjust for STI if we know of a base model for the requested model name
594
604
  # %%% Does not yet work with namespaced model names. Perhaps prefix with plural_class_name when doing the lookups here.
@@ -603,7 +613,7 @@ Module.class_exec do
603
613
  end
604
614
  # Maybe, just maybe there's a database table that will satisfy this need
605
615
  if (matching = [table_name, singular_table_name, plural_class_name, model_name].find { |m| relations.key?(schema_name ? "#{schema_name}.#{m}" : m) })
606
- Object.send(:build_model, schema_name, model_name, singular_table_name, table_name, relations, matching)
616
+ Object.send(:build_model, schema_name, inheritable_name, model_name, singular_table_name, table_name, relations, matching)
607
617
  end
608
618
  end
609
619
  end
@@ -631,12 +641,12 @@ class Object
631
641
 
632
642
  private
633
643
 
634
- def build_model(schema_name, model_name, singular_table_name, table_name, relations, matching)
644
+ def build_model(schema_name, inheritable_name, model_name, singular_table_name, table_name, relations, matching)
635
645
  full_name = if (::Brick.config.schema_behavior[:multitenant] && Object.const_defined?('Apartment') && schema_name == Apartment.default_schema)
636
646
  relation = relations["#{schema_name}.#{matching}"]
637
- model_name
647
+ inheritable_name || model_name
638
648
  elsif schema_name.blank?
639
- model_name
649
+ inheritable_name || model_name
640
650
  else # Prefix the schema to the table name + prefix the schema namespace to the class name
641
651
  schema_module = if schema_name.instance_of?(Module) # from an auto-STI namespace?
642
652
  schema_name
@@ -644,7 +654,7 @@ class Object
644
654
  matching = "#{schema_name}.#{matching}"
645
655
  (Brick.db_schemas[schema_name] ||= self.const_get(schema_name.singularize.camelize))
646
656
  end
647
- "#{schema_module&.name}::#{model_name}"
657
+ "#{schema_module&.name}::#{inheritable_name || model_name}"
648
658
  end
649
659
 
650
660
  return if ((is_view = (relation ||= relations[matching]).key?(:isView)) && ::Brick.config.skip_database_views) ||
@@ -653,12 +663,14 @@ class Object
653
663
  # Are they trying to use a pluralised class name such as "Employees" instead of "Employee"?
654
664
  if table_name == singular_table_name && !ActiveSupport::Inflector.inflections.uncountable.include?(table_name)
655
665
  unless ::Brick.config.sti_namespace_prefixes&.key?("::#{singular_table_name.camelize}::")
656
- puts "Warning: Class name for a model that references table \"#{matching}\" should be \"#{ActiveSupport::Inflector.singularize(model_name)}\"."
666
+ puts "Warning: Class name for a model that references table \"#{matching
667
+ }\" should be \"#{ActiveSupport::Inflector.singularize(inheritable_name || model_name)}\"."
657
668
  end
658
669
  return
659
670
  end
660
671
 
661
- if (base_model = ::Brick.sti_models[full_name]&.fetch(:base, nil) || ::Brick.existing_stis[full_name]&.constantize)
672
+ full_model_name = full_name.split('::').tap { |fn| fn[-1] = model_name }.join('::')
673
+ if (base_model = ::Brick.sti_models[full_model_name]&.fetch(:base, nil) || ::Brick.existing_stis[full_model_name]&.constantize)
662
674
  is_sti = true
663
675
  else
664
676
  base_model = ::Brick.config.models_inherit_from || ActiveRecord::Base
@@ -666,9 +678,21 @@ class Object
666
678
  hmts = nil
667
679
  code = +"class #{full_name} < #{base_model.name}\n"
668
680
  built_model = Class.new(base_model) do |new_model_class|
669
- (schema_module || Object).const_set(model_name.to_sym, new_model_class)
681
+ (schema_module || Object).const_set((inheritable_name || model_name).to_sym, new_model_class)
682
+ if inheritable_name
683
+ new_model_class.define_singleton_method :inherited do |subclass|
684
+ super(subclass)
685
+ if subclass.name == model_name
686
+ puts "#{full_model_name} properly extends from #{full_name}"
687
+ else
688
+ puts "should be \"class #{model_name} < #{inheritable_name}\"\n (not \"#{subclass.name} < #{inheritable_name}\")"
689
+ end
690
+ end
691
+ self.abstract_class = true
692
+ code << " self.abstract_class = true\n"
693
+ end
670
694
  # Accommodate singular or camel-cased table names such as "order_detail" or "OrderDetails"
671
- code << " self.table_name = '#{self.table_name = matching}'\n" unless table_name == matching
695
+ code << " self.table_name = '#{self.table_name = matching}'\n" if inheritable_name || table_name != matching
672
696
 
673
697
  # Override models backed by a view so they return true for #is_view?
674
698
  # (Dynamically-created controllers and view templates for such models will then act in a read-only way)
@@ -755,9 +779,12 @@ class Object
755
779
  options = { through: through.to_sym }
756
780
  if relation[:fks].any? { |k, v| v[:assoc_name] == hmt_name }
757
781
  hmt_name = "#{hmt_name.singularize}_#{fk.first[:assoc_name]}"
758
- # binding.pry if relation[:fks].any? { |k, v| v[:assoc_name] == hmt_name }
759
- options[:class_name] = fk.first[:inverse_table].singularize.camelize
760
- options[:foreign_key] = fk.first[:fk].to_sym
782
+ # Was:
783
+ # options[:class_name] = fk.first[:inverse_table].singularize.camelize
784
+ # options[:foreign_key] = fk.first[:fk].to_sym
785
+ far_assoc = relations[fk.first[:inverse_table]][:fks].find { |_k, v| v[:assoc_name] == fk.last }
786
+ options[:class_name] = far_assoc.last[:inverse_table].singularize.camelize
787
+ options[:foreign_key] = far_assoc.last[:fk].to_sym
761
788
  end
762
789
  options[:source] = fk.last.to_sym unless hmt_name.singularize == fk.last
763
790
  code << " has_many :#{hmt_name}#{options.map { |opt| ", #{opt.first}: #{opt.last.inspect}" }.join}\n"
@@ -880,19 +907,19 @@ class Object
880
907
  { 'url': 'https://{defaultHost}', 'variables': { 'defaultHost': { 'default': 'www.example.com' } } }
881
908
  ]
882
909
  }
883
- json['paths'] = relations.each_with_object({}) do |v, s|
884
- # next if v.last[:is_view]
885
-
910
+ json['paths'] = relations.inject({}) do |s, v|
886
911
  s["/api/v1/#{v.first}"] = {
887
912
  'get': {
888
- 'summary': 'list #{v.first}',
913
+ 'summary': "list #{v.first}",
889
914
  'parameters': v.last[:cols].map { |k, v| { 'name' => k, 'schema': { 'type': v.first } } },
890
915
  'responses': { '200': { 'description': 'successful' } }
891
916
  }
892
917
  }
918
+ # next if v.last[:isView]
919
+
893
920
  s["/api/v1/#{v.first}/{id}"] = {
894
921
  'patch': {
895
- 'summary': 'update a #{v.first.singularize}',
922
+ 'summary': "update a #{v.first.singularize}",
896
923
  'parameters': v.last[:cols].reject { |k, v| Brick.config.metadata_columns.include?(k) }.map do |k, v|
897
924
  { 'name' => k, 'schema': { 'type': v.first } }
898
925
  end,
@@ -918,8 +945,8 @@ class Object
918
945
  # }
919
946
  # ],
920
947
  }
948
+ s
921
949
  end
922
- # binding.pry
923
950
  render inline: json.to_json, content_type: request.format
924
951
  return
925
952
  end
@@ -936,7 +963,8 @@ class Object
936
963
  return
937
964
  end
938
965
 
939
- order = pk.each_with_object([]) { |pk_part, s| s << "#{model.table_name}.#{pk_part}" }
966
+ quoted_table_name = model.table_name.split('.').map { |x| "\"#{x}\"" }.join('.')
967
+ order = pk.each_with_object([]) { |pk_part, s| s << "#{quoted_table_name}.\"#{pk_part}\"" }
940
968
  ar_relation = order.present? ? model.order("#{order.join(', ')}") : model.all
941
969
  @_brick_params = ar_relation.brick_select(params, (selects = []), (bt_descrip = {}), (hm_counts = {}), (join_array = ::Brick::JoinArray.new))
942
970
  # %%% Add custom HM count columns
@@ -951,7 +979,8 @@ class Object
951
979
  @_brick_join_array = join_array
952
980
  end
953
981
 
954
- if model&.primary_key
982
+ is_pk_string = nil
983
+ if (pk_col = model&.primary_key)
955
984
  code << " def show\n"
956
985
  code << (find_by_id = " id = params[:id]&.split(/[\\/,_]/)
957
986
  id = id.first if id.is_a?(Array) && id.length == 1
@@ -959,7 +988,12 @@ class Object
959
988
  code << " end\n"
960
989
  self.define_method :show do
961
990
  ::Brick.set_db_schema(params)
962
- id = params[:id]&.split(/[\/,_]/)
991
+ id = if model.columns_hash[pk_col]&.type == :string
992
+ is_pk_string = true
993
+ params[:id]
994
+ else
995
+ params[:id]&.split(/[\/,_]/)
996
+ end
963
997
  id = id.first if id.is_a?(Array) && id.length == 1
964
998
  instance_variable_set("@#{singular_table_name}".to_sym, model.find(id))
965
999
  end
@@ -998,7 +1032,7 @@ class Object
998
1032
  # return
999
1033
  end
1000
1034
 
1001
- id = params[:id]&.split(/[\/,_]/)
1035
+ id = is_pk_string ? params[:id] : params[:id]&.split(/[\/,_]/)
1002
1036
  id = id.first if id.is_a?(Array) && id.length == 1
1003
1037
  instance_variable_set("@#{singular_table_name}".to_sym, (obj = model.find(id)))
1004
1038
  obj = obj.first if obj.is_a?(Array)
@@ -1024,19 +1058,15 @@ class Object
1024
1058
  end
1025
1059
 
1026
1060
  def _brick_get_hm_assoc_name(relation, hm_assoc)
1027
- if relation[:hm_counts][hm_assoc[:assoc_name]]&.> 1
1028
- # binding.pry if (same_name = relation[:fks].find { |x| x.last[:assoc_name] == hm_assoc[:assoc_name] && x.last != hm_assoc }) #&&
1029
- # x.last[:alternate_name] == hm_assoc[:alternate_name] })
1030
- # relation[:fks].any? { |k, v| v[:assoc_name] == new_alt_name }
1061
+ if (relation[:hm_counts][hm_assoc[:assoc_name]]&.> 1) &&
1062
+ hm_assoc[:alternate_name] != hm_assoc[:inverse][:assoc_name]
1031
1063
  plural = ActiveSupport::Inflector.pluralize(hm_assoc[:alternate_name])
1032
- # binding.pry if hm_assoc[:assoc_name] == 'issue_issue_duplicates'
1033
1064
  new_alt_name = (hm_assoc[:alternate_name] == name.underscore) ? "#{hm_assoc[:assoc_name].singularize}_#{plural}" : plural
1034
1065
  # uniq = 1
1035
1066
  # while same_name = relation[:fks].find { |x| x.last[:assoc_name] == hm_assoc[:assoc_name] && x.last != hm_assoc }
1036
1067
  # hm_assoc[:assoc_name] = "#{hm_assoc_name}_#{uniq += 1}"
1037
1068
  # end
1038
1069
  # puts new_alt_name
1039
- # binding.pry if new_alt_name == 'issue_duplicates'
1040
1070
  # hm_assoc[:assoc_name] = new_alt_name
1041
1071
  [new_alt_name, true]
1042
1072
  else
@@ -1078,9 +1108,11 @@ module ActiveRecord::ConnectionHandling
1078
1108
  # Only for Postgres? (Doesn't work in sqlite3)
1079
1109
  # puts ActiveRecord::Base.execute_sql("SELECT current_setting('SEARCH_PATH')").to_a.inspect
1080
1110
 
1111
+ is_postgres = nil
1081
1112
  schema_sql = 'SELECT NULL AS table_schema;'
1082
1113
  case ActiveRecord::Base.connection.adapter_name
1083
1114
  when 'PostgreSQL'
1115
+ is_postgres = true
1084
1116
  if (is_multitenant = (multitenancy = ::Brick.config.schema_behavior[:multitenant]) &&
1085
1117
  (sta = multitenancy[:schema_to_analyse]) != 'public')
1086
1118
  ::Brick.default_schema = schema = sta
@@ -1090,12 +1122,14 @@ module ActiveRecord::ConnectionHandling
1090
1122
  when 'Mysql2'
1091
1123
  ::Brick.default_schema = schema = ActiveRecord::Base.connection.current_database
1092
1124
  when 'SQLite'
1125
+ # %%% Retrieve internal ActiveRecord table names like this:
1126
+ # ActiveRecord::Base.internal_metadata_table_name, ActiveRecord::Base.schema_migrations_table_name
1093
1127
  sql = "SELECT m.name AS relation_name, UPPER(m.type) AS table_type,
1094
1128
  p.name AS column_name, p.type AS data_type,
1095
1129
  CASE p.pk WHEN 1 THEN 'PRIMARY KEY' END AS const
1096
1130
  FROM sqlite_master AS m
1097
1131
  INNER JOIN pragma_table_info(m.name) AS p
1098
- WHERE m.name NOT IN ('ar_internal_metadata', 'schema_migrations')
1132
+ WHERE m.name NOT IN (?, ?)
1099
1133
  ORDER BY m.name, p.cid"
1100
1134
  else
1101
1135
  puts "Unfamiliar with connection adapter #{ActiveRecord::Base.connection.adapter_name}"
@@ -1123,7 +1157,11 @@ module ActiveRecord::ConnectionHandling
1123
1157
  end
1124
1158
  end
1125
1159
 
1126
- sql ||= "SELECT t.table_schema AS schema, t.table_name AS relation_name, t.table_type,
1160
+ # %%% Retrieve internal ActiveRecord table names like this:
1161
+ # ActiveRecord::Base.internal_metadata_table_name, ActiveRecord::Base.schema_migrations_table_name
1162
+ # For if it's not SQLite -- so this is the Postgres and MySQL version
1163
+ sql ||= "SELECT t.table_schema AS schema, t.table_name AS relation_name, t.table_type,#{"
1164
+ pg_catalog.obj_description((t.table_schema || '.' || t.table_name)::regclass, 'pg_class') AS table_description," if is_postgres}
1127
1165
  c.column_name, c.data_type,
1128
1166
  COALESCE(c.character_maximum_length, c.numeric_precision) AS max_length,
1129
1167
  tc.constraint_type AS const, kcu.constraint_name AS \"key\",
@@ -1144,13 +1182,14 @@ module ActiveRecord::ConnectionHandling
1144
1182
  WHERE t.table_schema NOT IN ('information_schema', 'pg_catalog')#{"
1145
1183
  AND t.table_schema = COALESCE(current_setting('SEARCH_PATH'), 'public')" if schema }
1146
1184
  -- AND t.table_type IN ('VIEW') -- 'BASE TABLE', 'FOREIGN TABLE'
1147
- AND t.table_name NOT IN ('pg_stat_statements', 'ar_internal_metadata', 'schema_migrations')
1185
+ AND t.table_name NOT IN ('pg_stat_statements', ?, ?)
1148
1186
  ORDER BY 1, t.table_type DESC, c.ordinal_position"
1149
1187
  measures = []
1150
1188
  case ActiveRecord::Base.connection.adapter_name
1151
1189
  when 'PostgreSQL', 'SQLite' # These bring back a hash for each row because the query uses column aliases
1152
1190
  # schema ||= 'public' if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
1153
- ActiveRecord::Base.execute_sql(sql).each do |r|
1191
+ ar_imtn = ActiveRecord.version >= ::Gem::Version.new('5.0') ? ActiveRecord::Base.internal_metadata_table_name : ''
1192
+ ActiveRecord::Base.execute_sql(sql, ActiveRecord::Base.schema_migrations_table_name, ar_imtn).each do |r|
1154
1193
  # If Apartment gem lists the table as being associated with a non-tenanted model then use whatever it thinks
1155
1194
  # is the default schema, usually 'public'.
1156
1195
  schema_name = if ::Brick.config.schema_behavior[:multitenant]
@@ -1161,6 +1200,7 @@ module ActiveRecord::ConnectionHandling
1161
1200
  relation_name = schema_name ? "#{schema_name}.#{r['relation_name']}" : r['relation_name']
1162
1201
  relation = relations[relation_name]
1163
1202
  relation[:isView] = true if r['table_type'] == 'VIEW'
1203
+ relation[:description] = r['table_description'] if r['table_description']
1164
1204
  col_name = r['column_name']
1165
1205
  key = case r['const']
1166
1206
  when 'PRIMARY KEY'
@@ -1259,11 +1299,25 @@ module ActiveRecord::ConnectionHandling
1259
1299
  end
1260
1300
  end
1261
1301
 
1262
- puts "\nClasses that can be built from tables:"
1263
- relations.select { |_k, v| !v.key?(:isView) }.keys.each { |k| puts ActiveSupport::Inflector.singularize(k).camelize }
1264
- unless (views = relations.select { |_k, v| v.key?(:isView) }).empty?
1302
+ apartment = Object.const_defined?('Apartment') && Apartment
1303
+ tables = []
1304
+ views = []
1305
+ relations.each do |k, v|
1306
+ name_parts = k.split('.')
1307
+ if v.key?(:isView)
1308
+ views
1309
+ else
1310
+ name_parts.shift if apartment && name_parts.length > 1 && name_parts.first == Apartment.default_schema
1311
+ tables
1312
+ end << name_parts.map { |x| x.singularize.camelize }.join('::')
1313
+ end
1314
+ unless tables.empty?
1315
+ puts "\nClasses that can be built from tables:"
1316
+ tables.sort.each { |x| puts x }
1317
+ end
1318
+ unless views.empty?
1265
1319
  puts "\nClasses that can be built from views:"
1266
- views.keys.each { |k| puts ActiveSupport::Inflector.singularize(k).camelize }
1320
+ views.sort.each { |x| puts x }
1267
1321
  end
1268
1322
 
1269
1323
  ::Brick.load_additional_references if initializer_loaded
@@ -1306,7 +1360,8 @@ module Brick
1306
1360
  end
1307
1361
  # %%% Temporary schema patch
1308
1362
  for_tbl = fk[1]
1309
- fk[0] = Apartment.default_schema if Object.const_defined?('Apartment') && Apartment.excluded_models.include?(for_tbl.singularize.camelize)
1363
+ apartment = Object.const_defined?('Apartment') && Apartment
1364
+ fk[0] = Apartment.default_schema if apartment && apartment.excluded_models.include?(for_tbl.singularize.camelize)
1310
1365
  fk[1] = "#{fk[0]}.#{fk[1]}" if fk[0] # && fk[0] != ::Brick.default_schema
1311
1366
  bts = (relation = relations.fetch(fk[1], nil))&.fetch(:fks) { relation[:fks] = {} }
1312
1367
 
@@ -1321,7 +1376,7 @@ module Brick
1321
1376
  is_schema = if ::Brick.config.schema_behavior[:multitenant]
1322
1377
  # If Apartment gem lists the primary table as being associated with a non-tenanted model
1323
1378
  # then use 'public' schema for the primary table
1324
- if Object.const_defined?('Apartment') && Apartment.excluded_models.include?(fk[4].singularize.camelize)
1379
+ if apartment && apartment&.excluded_models.include?(fk[4].singularize.camelize)
1325
1380
  fk[3] = Apartment.default_schema
1326
1381
  true
1327
1382
  end
@@ -1398,12 +1453,11 @@ module Brick
1398
1453
  assoc_hm[:alternate_name] = "#{assoc_hm[:alternate_name]}_#{bt_assoc_name}" unless assoc_hm[:alternate_name] == bt_assoc_name
1399
1454
  assoc_hm[:inverse] = assoc_bt
1400
1455
  else
1401
- inv_tbl = if ::Brick.config.schema_behavior[:multitenant] && Object.const_defined?('Apartment') && fk[0] == Apartment.default_schema
1456
+ inv_tbl = if ::Brick.config.schema_behavior[:multitenant] && apartment && fk[0] == Apartment.default_schema
1402
1457
  for_tbl
1403
1458
  else
1404
1459
  fk[1]
1405
1460
  end
1406
- # binding.pry if inv_tbl == 'issue_issue_duplicates' # inverse_table goofed?
1407
1461
  assoc_hm = hms[hm_cnstr_name] = { is_bt: false, fk: fk[2], assoc_name: for_tbl.pluralize, alternate_name: bt_assoc_name,
1408
1462
  inverse_table: inv_tbl, inverse: assoc_bt }
1409
1463
  assoc_hm[:polymorphic] = true if is_polymorphic
@@ -124,8 +124,15 @@ module Brick
124
124
  schema_options = ::Brick.db_schemas.keys.each_with_object(+'') { |v, s| s << "<option value=\"#{v}\">#{v}</option>" }.html_safe
125
125
  # %%% If we are not auto-creating controllers (or routes) then omit by default, and if enabled anyway, such as in a development
126
126
  # environment or whatever, then get either the controllers or routes list instead
127
- table_options = (::Brick.relations.keys - ::Brick.config.exclude_tables).sort
128
- .each_with_object(+'') { |v, s| s << "<option value=\"#{v.underscore.gsub('.', '/').pluralize}\">#{v}</option>" }.html_safe
127
+ apartment_default_schema = ::Brick.config.schema_behavior[:multitenant] && Object.const_defined?('Apartment') && Apartment.default_schema
128
+ table_options = (::Brick.relations.keys - ::Brick.config.exclude_tables).map do |tbl|
129
+ if (tbl_parts = tbl.split('.')).first == apartment_default_schema
130
+ tbl = tbl_parts.last
131
+ end
132
+ tbl
133
+ end.sort.each_with_object(+'') do |v, s|
134
+ s << "<option value=\"#{v.underscore.gsub('.', '/').pluralize}\">#{v}</option>"
135
+ end.html_safe
129
136
  css = +"<style>
130
137
  #dropper {
131
138
  background-color: #eee;
@@ -209,12 +216,17 @@ input[type=submit] {
209
216
  <% def is_bcrypt?(val)
210
217
  val.is_a?(String) && val.length == 60 && val.start_with?('$2a$')
211
218
  end
212
- def hide_bcrypt(val)
219
+ def hide_bcrypt(val, max_len = 200)
213
220
  if is_bcrypt?(val)
214
221
  '(hidden)'
215
- elsif val.is_a?(String) && val.encoding.name != 'UTF-8'
216
- val[0..1000].force_encoding('UTF-8')
217
222
  else
223
+ if val.is_a?(String)
224
+ if val.length > max_len
225
+ val = val[0...max_len]
226
+ val << '...'
227
+ end
228
+ val.force_encoding('UTF-8') unless val.encoding.name == 'UTF-8'
229
+ end
218
230
  val
219
231
  end
220
232
  end %>"
@@ -238,46 +250,51 @@ end %>"
238
250
  poly_cols = #{poly_cols.inspect} %>"
239
251
  end
240
252
 
241
- # %%% When doing schema select, if there's an ID then remove it, or if we're on a new page go to index
253
+ # %%% When doing schema select, if we're on a new page go to index
242
254
  script = "<script>
243
255
  var schemaSelect = document.getElementById(\"schema\");
256
+ var tblSelect = document.getElementById(\"tbl\");
244
257
  var brickSchema;
245
- if (schemaSelect) {
246
- brickSchema = changeout(location.href, \"_brick_schema\");
247
- if (brickSchema) {
248
- [... document.getElementsByTagName(\"A\")].forEach(function (a) { a.href = changeout(a.href, \"_brick_schema\", brickSchema); });
258
+
259
+ // This PageTransitionEvent fires when the page first loads, as well as after any other history
260
+ // transition such as when using the browser's Back and Forward buttons.
261
+ window.addEventListener(\"pageshow\", function() {
262
+ if (schemaSelect) { // First drop-down is only present if multitenant
263
+ brickSchema = changeout(location.href, \"_brick_schema\");
264
+ if (brickSchema) {
265
+ [... document.getElementsByTagName(\"A\")].forEach(function (a) { a.href = changeout(a.href, \"_brick_schema\", brickSchema); });
266
+ }
267
+ schemaSelect.value = brickSchema || \"public\";
268
+ schemaSelect.focus();
269
+ schemaSelect.addEventListener(\"change\", function () {
270
+ // If there's an ID then remove it (trim after selected table)
271
+ location.href = changeout(location.href, \"_brick_schema\", this.value, tblSelect.value);
272
+ });
249
273
  }
250
- schemaSelect.value = brickSchema || \"public\";
251
- schemaSelect.focus();
252
- schemaSelect.addEventListener(\"change\", function () {
253
- location.href = changeout(location.href, \"_brick_schema\", this.value);
254
- });
255
- }
256
- [... document.getElementsByTagName(\"FORM\")].forEach(function (form) {
257
- if (brickSchema)
258
- form.action = changeout(form.action, \"_brick_schema\", brickSchema);
259
- form.addEventListener('submit', function (ev) {
260
- [... ev.target.getElementsByTagName(\"SELECT\")].forEach(function (select) {
261
- if (select.value === \"^^^brick_NULL^^^\")
262
- select.value = null;
274
+ [... document.getElementsByTagName(\"FORM\")].forEach(function (form) {
275
+ if (brickSchema)
276
+ form.action = changeout(form.action, \"_brick_schema\", brickSchema);
277
+ form.addEventListener('submit', function (ev) {
278
+ [... ev.target.getElementsByTagName(\"SELECT\")].forEach(function (select) {
279
+ if (select.value === \"^^^brick_NULL^^^\")
280
+ select.value = null;
281
+ });
282
+ return true;
263
283
  });
264
- return true;
265
284
  });
266
- });
267
285
 
268
- var tblSelect = document.getElementById(\"tbl\");
269
- if (tblSelect) {
270
- tblSelect.value = changeout(location.href)[0];
271
- if (tblSelect.selectedIndex < 0) tblSelect.value = changeout(location.href)[1];
272
- tblSelect.addEventListener(\"change\", function () {
273
- var lhr = changeout(location.href, null, this.value);
274
- if (brickSchema)
275
- lhr = changeout(lhr, \"_brick_schema\", schemaSelect.value);
276
- location.href = lhr;
277
- });
278
- }
286
+ if (tblSelect) { // Always present
287
+ tblSelect.value = changeout(location.href)[schemaSelect ? 1 : 0];
288
+ tblSelect.addEventListener(\"change\", function () {
289
+ var lhr = changeout(location.href, null, this.value);
290
+ if (brickSchema)
291
+ lhr = changeout(lhr, \"_brick_schema\", schemaSelect.value);
292
+ location.href = lhr;
293
+ });
294
+ }
295
+ });
279
296
 
280
- function changeout(href, param, value) {
297
+ function changeout(href, param, value, trimAfter) {
281
298
  var hrefParts = href.split(\"?\");
282
299
  if (param === undefined || param === null) {
283
300
  hrefParts = hrefParts[0].split(\"://\");
@@ -288,6 +305,11 @@ function changeout(href, param, value) {
288
305
  else
289
306
  return hrefParts[0] + \"://\" + pathParts[0] + \"/\" + value;
290
307
  }
308
+ if (trimAfter) {
309
+ var pathParts = hrefParts[0].split(\"/\");
310
+ while (pathParts.lastIndexOf(trimAfter) != pathParts.length - 1) pathParts.pop();
311
+ hrefParts[0] = pathParts.join(\"/\");
312
+ }
291
313
  var params = hrefParts.length > 1 ? hrefParts[1].split(\"&\") : [];
292
314
  params = params.reduce(function (s, v) { var parts = v.split(\"=\"); s[parts[0]] = parts[1]; return s; }, {});
293
315
  if (value === undefined) return params[param];
@@ -353,7 +375,6 @@ function changeout(href, param, value) {
353
375
 
354
376
  async function updateSignInStatus(isSignedIn) {
355
377
  if (isSignedIn) {
356
- console.log(\"turds!\");
357
378
  await gapi.client.sheets.spreadsheets.create({
358
379
  properties: {
359
380
  title: #{table_name.inspect},
@@ -394,18 +415,19 @@ function changeout(href, param, value) {
394
415
  end
395
416
  # %%% Instead of our current "for Janet Leverling (Employee)" kind of link we previously had this code that did a "where x = 123" thing:
396
417
  # (where <%= @_brick_params.each_with_object([]) { |v, s| s << \"#\{v.first\} = #\{v.last.inspect\}\" }.join(', ') %>)
397
- "#{css}
418
+ x = "#{css}
398
419
  <p style=\"color: green\"><%= notice %></p>#{"
399
420
  <select id=\"schema\">#{schema_options}</select>" if ::Brick.config.schema_behavior[:multitenant] && ::Brick.db_schemas.length > 1}
400
421
  <select id=\"tbl\">#{table_options}</select>
401
- <h1>#{model_plural = model_name.pluralize}</h1>#{template_link}
402
-
403
- <% if @_brick_params&.present? %>
422
+ <h1>#{model_plural = model_name.pluralize}</h1>#{template_link}<%
423
+ if (relation = Brick.relations[#{model_name}.table_name])[:description] %><%=
424
+ relation.fetch(:description, nil) %><br><%
425
+ end
426
+ if @_brick_params&.present? %>
404
427
  <% if @_brick_params.length == 1 # %%% Does not yet work with composite keys
405
428
  k, id = @_brick_params.first
406
429
  id = id.first if id.is_a?(Array) && id.length == 1
407
430
  origin = (key_parts = k.split('.')).length == 1 ? #{model_name} : #{model_name}.reflect_on_association(key_parts.first).klass
408
- # binding.pry
409
431
  if (destination_fk = Brick.relations[origin.table_name][:fks].values.find { |fk| puts fk.inspect; fk[:fk] == key_parts.last }) &&
410
432
  (obj = (destination = origin.reflect_on_association(destination_fk[:assoc_name])&.klass)&.find(id)) %>
411
433
  <h3>for <%= link_to \"#{"#\{obj.brick_descrip\} (#\{destination.name\})\""}, send(\"#\{destination.name.underscore.tr('/', '_')\}_path\".to_sym, id) %></h3><%
@@ -415,19 +437,23 @@ function changeout(href, param, value) {
415
437
  <% end %>
416
438
  <table id=\"#{table_name}\">
417
439
  <thead><tr>#{'<th></th>' if pk.present?}
418
- <% @#{table_name}.columns.map(&:name).each do |col| %>
419
- <% next if (#{(pk || []).inspect}.include?(col) && #{model_name}.column_for_attribute(col).type == :integer && !bts.key?(col)) ||
420
- ::Brick.config.metadata_columns.include?(col) || poly_cols.include?(col) %>
421
- <th>
422
- <% if (bt = bts[col]) %>
440
+ <% col_order = []
441
+ @#{table_name}.columns.each do |col|
442
+ col_name = col.name
443
+ next if (#{(pk || []).inspect}.include?(col_name) && col.type == :integer && !bts.key?(col_name)) ||
444
+ ::Brick.config.metadata_columns.include?(col_name) || poly_cols.include?(col_name)
445
+
446
+ col_order << col_name %>
447
+ <th<%= \" title = \\\"#\{col.comment}\\\"\".html_safe unless col.comment.blank? %>><%
448
+ if (bt = bts[col_name]) %>
423
449
  BT <%
424
450
  bt[1].each do |bt_pair| %><%=
425
451
  bt_pair.first.bt_link(bt.first) %> <%
426
452
  end %><%
427
453
  else %><%=
428
- col %><%
429
- end %>
430
- </th>
454
+ col_name %><%
455
+ end
456
+ %></th>
431
457
  <% end %>
432
458
  <%# Consider getting the name from the association -- h.first.name -- if a more \"friendly\" alias should be used for a screwy table name %>
433
459
  #{hms_headers.map { |h| "<th>#{h[1]} <%= link_to('#{h[2]}', #{h.first.klass.name.underscore.tr('/', '_').pluralize}_path) %></th>\n" }.join}
@@ -437,12 +463,10 @@ function changeout(href, param, value) {
437
463
  <% @#{table_name}.each do |#{obj_name}| %>
438
464
  <tr>#{"
439
465
  <td><%= link_to '⇛', #{path_obj_name}_path(#{obj_pk}), { class: 'big-arrow' } %></td>" if obj_pk}
440
- <% #{obj_name}.attributes.each do |k, val| %>
441
- <% next if (#{(obj_pk || []).inspect}.include?(k) && #{model_name}.column_for_attribute(k).type == :integer && !bts.key?(k)) ||
442
- ::Brick.config.metadata_columns.include?(k) || poly_cols.include?(k) || k.start_with?('_brfk_') || (k.start_with?('_br_') && (k.length == 63 || k.end_with?('_ct'))) %>
466
+ <% col_order.each do |col_name|
467
+ val = #{obj_name}.attributes[col_name] %>
443
468
  <td>
444
- <% if (bt = bts[k]) %>
445
- <%# binding.pry # Postgres column names are limited to 63 characters %>
469
+ <% if (bt = bts[col_name]) %>
446
470
  <% if bt[2] # Polymorphic?
447
471
  bt_class = #{obj_name}.send(\"#\{bt.first\}_type\")
448
472
  base_class = (::Brick.existing_stis[bt_class] || bt_class).constantize.base_class.name.underscore
@@ -451,6 +475,7 @@ function changeout(href, param, value) {
451
475
  send(\"#\{base_class\}_path\".to_sym, poly_id)) if poly_id %><%
452
476
  else
453
477
  bt_txt = (bt_class = bt[1].first.first).brick_descrip(
478
+ # 0..62 because Postgres column names are limited to 63 characters
454
479
  #{obj_name}, (descrips = @_brick_bt_descrip[bt.first][bt_class])[0..-2].map { |z| #{obj_name}.send(z.last[0..62]) }, (bt_id_col = descrips.last)
455
480
  )
456
481
  bt_id = #{obj_name}.send(*bt_id_col) if bt_id_col&.present? %>
@@ -470,13 +495,18 @@ function changeout(href, param, value) {
470
495
 
471
496
  #{"<hr><%= link_to \"New #{obj_name}\", new_#{path_obj_name}_path %>" unless @_brick_model.is_view?}
472
497
  #{script}"
498
+ puts x
499
+ x
473
500
  when 'show', 'update'
474
501
  "#{css}
475
502
  <p style=\"color: green\"><%= notice %></p>#{"
476
503
  <select id=\"schema\">#{schema_options}</select>" if ::Brick.config.schema_behavior[:multitenant] && ::Brick.db_schemas.length > 1}
477
504
  <select id=\"tbl\">#{table_options}</select>
478
- <h1>#{model_name}: <%= (obj = @#{obj_name})&.brick_descrip || controller_name %></h1>
479
- <%= link_to '(See all #{obj_name.pluralize})', #{path_obj_name.pluralize}_path %>
505
+ <h1>#{model_name}: <%= (obj = @#{obj_name})&.brick_descrip || controller_name %></h1><%
506
+ if (relation = Brick.relations[#{model_name}.table_name])[:description] %><%=
507
+ relation.fetch(:description, nil) %><br><%
508
+ end
509
+ %><%= link_to '(See all #{obj_name.pluralize})', #{path_obj_name.pluralize}_path %>
480
510
  <% if obj %>
481
511
  <%= # path_options = [obj.#{pk}]
482
512
  # path_options << { '_brick_schema': } if
@@ -484,11 +514,12 @@ function changeout(href, param, value) {
484
514
  form_for(obj.becomes(#{model_name})) do |f| %>
485
515
  <table>
486
516
  <% has_fields = false
487
- @#{obj_name}.attributes.each do |k, val| %>
517
+ @#{obj_name}.attributes.each do |k, val|
518
+ col = #{model_name}.columns_hash[k] %>
488
519
  <tr>
489
520
  <% next if (#{(pk || []).inspect}.include?(k) && !bts.key?(k)) ||
490
521
  ::Brick.config.metadata_columns.include?(k) %>
491
- <th class=\"show-field\">
522
+ <th class=\"show-field\"<%= \" title = \\\"#\{col.comment}\\\"\".html_safe unless col.comment.blank? %>>
492
523
  <% has_fields = true
493
524
  if (bt = bts[k])
494
525
  # Add a final member in this array with descriptive options to be used in <select> drop-downs
@@ -533,7 +564,7 @@ function changeout(href, param, value) {
533
564
  <% else case #{model_name}.column_for_attribute(k).type
534
565
  when :string, :text %>
535
566
  <% if is_bcrypt?(val) # || .readonly? %>
536
- <%= hide_bcrypt(val) %>
567
+ <%= hide_bcrypt(val, 1000) %>
537
568
  <% else %>
538
569
  <div class=\"wide-input\"><%= f.text_field k.to_sym %></div>
539
570
  <% end %>
@@ -566,7 +597,7 @@ function changeout(href, param, value) {
566
597
  s << "<table id=\"#{hm_name}\">
567
598
  <tr><th>#{hm[3]}</th></tr>
568
599
  <% collection = @#{obj_name}.#{hm_name}
569
- collection = collection.is_a?(ActiveRecord::Associations::CollectionProxy) ? collection.order(#{pk.inspect}) : [collection]
600
+ collection = collection.is_a?(ActiveRecord::Associations::CollectionProxy) ? collection.order(#{pk.inspect}) : [collection].compact
570
601
  if collection.empty? %>
571
602
  <tr><td>(none)</td></tr>
572
603
  <% else %>
@@ -600,6 +631,7 @@ function changeout(href, param, value) {
600
631
 
601
632
  # Just in case it hadn't been done previously when we tried to load the brick initialiser,
602
633
  # go make sure we've loaded additional references (virtual foreign keys and polymorphic associations).
634
+ # (This should only happen if for whatever reason the initializer file was not exactly config/initializers/brick.rb.)
603
635
  ::Brick.load_additional_references
604
636
  end
605
637
  end
@@ -5,7 +5,7 @@ module Brick
5
5
  module VERSION
6
6
  MAJOR = 1
7
7
  MINOR = 0
8
- TINY = 33
8
+ TINY = 36
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
@@ -1,25 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'active_record/version'
4
-
5
- # ActiveRecord before 4.0 didn't have #version
6
- unless ActiveRecord.respond_to?(:version)
7
- module ActiveRecord
8
- def self.version
9
- ::Gem::Version.new(ActiveRecord::VERSION::STRING)
10
- end
11
- end
12
- end
13
-
14
- # In ActiveSupport older than 5.0, the duplicable? test tries to new up a BigDecimal,
15
- # and Ruby 2.6 and later deprecates #new. This removes the warning from BigDecimal.
16
- require 'bigdecimal'
17
- if (ruby_version = ::Gem::Version.new(RUBY_VERSION)) >= ::Gem::Version.new('2.6') &&
18
- ActiveRecord.version < ::Gem::Version.new('5.0')
19
- def BigDecimal.new(*args, **kwargs)
20
- BigDecimal(*args, **kwargs)
21
- end
22
- end
3
+ require 'brick/compatibility'
23
4
 
24
5
  # Allow ActiveRecord 4.0 and 4.1 to work with newer Ruby (>= 2.4) by avoiding a "stack level too deep"
25
6
  # error when ActiveSupport tries to smarten up Numeric by messing with Fixnum and Bignum at the end of:
@@ -45,8 +26,8 @@ end
45
26
  require 'brick/util'
46
27
 
47
28
  # Allow ActiveRecord < 3.2 to work with Ruby 2.7 and later
48
- if ActiveRecord.version < ::Gem::Version.new('3.2') &&
49
- ruby_version >= ::Gem::Version.new('2.7')
29
+ if (ruby_version = ::Gem::Version.new(RUBY_VERSION)) >= ::Gem::Version.new('2.7') &&
30
+ ActiveRecord.version < ::Gem::Version.new('3.2')
50
31
  # Remove circular reference for "now"
51
32
  ::Brick::Util._patch_require(
52
33
  'active_support/values/time_zone.rb', '/activesupport',
@@ -132,7 +113,6 @@ module Brick
132
113
  associatives = hms.each_with_object({}) do |hmt, s|
133
114
  if (through = hmt.last.options[:through])
134
115
  skip_hms[through] = nil
135
- # binding.pry if hmt.first == :issue_issues
136
116
  s[hmt.first] = hms[through] # End up with a hash of HMT names pointing to join-table associations
137
117
  elsif hmt.last.inverse_of.nil?
138
118
  puts "SKIPPING #{hmt.last.name.inspect}"
@@ -18,7 +18,8 @@ module Brick
18
18
  desc 'Generates an initializer file for configuring Brick'
19
19
 
20
20
  def create_initializer_file
21
- unless File.exist?(filename = 'config/initializers/brick.rb')
21
+ is_brick_file = File.exist?(filename = 'config/initializers/brick.rb')
22
+ if is_brick_file && ::Brick.config.schema_behavior[:multitenant] || !is_brick_file
22
23
  # See if we can make suggestions for additional_references and polymorphic associations
23
24
  resembles_fks = Hash.new { |h, k| h[k] = [] }
24
25
  possible_polymorphics = {}
@@ -223,7 +224,10 @@ module Brick
223
224
  # # Database schema to use when analysing existing data, such as deriving a list of polymorphic classes in the case that
224
225
  # # it wasn't originally specified.
225
226
  # Brick.schema_behavior = :namespaced
226
- # Brick.schema_behavior = { multitenant: { schema_to_analyse: 'engineering' } }
227
+ #{Brick.config.schema_behavior ? "Brick.schema_behavior = { multitenant: { schema_to_analyse: #{
228
+ Brick.config.schema_behavior[:multitenant][:schema_to_analyse].inspect}" :
229
+ "# Brick.schema_behavior = { multitenant: { schema_to_analyse: 'engineering'"
230
+ } } }
227
231
 
228
232
  # # Polymorphic associations are set up by providing a model name and polymorphic association name#{poly}
229
233
 
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.33
4
+ version: 1.0.36
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-06-21 00:00:00.000000000 Z
11
+ date: 2022-06-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -214,6 +214,7 @@ extensions: []
214
214
  extra_rdoc_files: []
215
215
  files:
216
216
  - lib/brick.rb
217
+ - lib/brick/compatibility.rb
217
218
  - lib/brick/config.rb
218
219
  - lib/brick/extensions.rb
219
220
  - lib/brick/frameworks/cucumber.rb