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 +4 -4
- data/lib/brick/compatibility.rb +25 -0
- data/lib/brick/extensions.rb +119 -65
- data/lib/brick/frameworks/rails/engine.rb +94 -62
- data/lib/brick/version_number.rb +1 -1
- data/lib/brick.rb +3 -23
- data/lib/generators/brick/install_generator.rb +6 -2
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6ef930474d4e1496812af0a626f57a2db1b05396c2dc46eb8f117c6fbf2f4df5
|
4
|
+
data.tar.gz: 8847971321e1a6178b340ef6929298d2d33edb1a1918584c43d67edc5b844a39
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
data/lib/brick/extensions.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
578
|
-
|
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
|
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
|
-
|
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"
|
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
|
-
#
|
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.
|
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':
|
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':
|
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
|
-
|
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
|
-
|
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 =
|
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
|
-
|
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 (
|
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
|
-
|
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',
|
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::
|
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
|
-
|
1263
|
-
|
1264
|
-
|
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.
|
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
|
-
|
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
|
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] &&
|
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
|
-
|
128
|
-
|
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
|
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
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
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
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
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
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
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
|
-
|
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
|
-
<%
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
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
|
-
|
429
|
-
end
|
430
|
-
|
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
|
-
<%
|
441
|
-
|
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[
|
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
|
-
|
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
|
data/lib/brick/version_number.rb
CHANGED
data/lib/brick.rb
CHANGED
@@ -1,25 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
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
|
49
|
-
|
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
|
-
|
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:
|
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.
|
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-
|
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
|