brick 1.0.100 → 1.0.101

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: ba0de7f332d1d98502a4e66bc4fda9b44d4f97fe6d6a259ac7527a856c726000
4
- data.tar.gz: 45898a638f4c944cf33e98ff73a41da97686819bbdfcc8534257c013a6b28582
3
+ metadata.gz: eba38d653370b0cc3e98f2adc82d8c475854440745bd35caab9a9a4253fc152c
4
+ data.tar.gz: 18ca517b90266cf5db711040a7f40c8e848600135ef0a39ad91da9cd2a0b1c89
5
5
  SHA512:
6
- metadata.gz: 28079c58b020d395845c681710c88db3e7a32ae312fbdf607ab496854aab37d29f3a9dfed78a2495a011b3817aed8259260a1d0d5ecd409803d89b4eda70b87f
7
- data.tar.gz: 834499603e05412ee19c2f5db90f55df1f927eff85a41488e4f57381065580aeb4477700596988e4cc630282268f40045d1831822bde2c80b659a23e257f692a
6
+ metadata.gz: 859f48999fb0e8d1010a701e29c9f0275f716b20f54b4348576f4dbff7f68da1eb83709a51a1a7acd7debaf4dc1f82e863048ef16cda6b5f59862246e0c50787
7
+ data.tar.gz: d93c3db79715f62705c0b8f2f5bd2640a2756e1fbcb6aa6a7cf017a18bc31fa5e98496ea41539611c149f84870f24596c105d146484519b7f040d2f36b25ce45
@@ -446,8 +446,13 @@ module ActiveRecord
446
446
  selects << if is_mysql
447
447
  "`#{tbl_no_schema}`.`#{col_name}`#{col_alias}"
448
448
  elsif is_postgres || is_mssql
449
- # Postgres can not use DISTINCT with any columns that are XML, so for any of those just convert to text
450
- cast_as_text = '::text' if is_distinct && Brick.relations[klass.table_name]&.[](:cols)&.[](col_name)&.first&.start_with?('xml')
449
+ if is_distinct # Postgres can not use DISTINCT with any columns that are XML or JSON
450
+ cast_as_text = if Brick.relations[klass.table_name]&.[](:cols)&.[](col_name)&.first == 'json'
451
+ '::jsonb' # Convert JSON to JSONB
452
+ elsif Brick.relations[klass.table_name]&.[](:cols)&.[](col_name)&.first&.start_with?('xml')
453
+ '::text' # Convert XML to text
454
+ end
455
+ end
451
456
  "\"#{tbl_no_schema}\".\"#{col_name}\"#{cast_as_text}#{col_alias}"
452
457
  elsif col.type # Could be Sqlite or Oracle
453
458
  if col_alias || !(/^[a-z0-9_]+$/ =~ col_name)
@@ -631,19 +636,26 @@ module ActiveRecord
631
636
  through_sources.map do |a|
632
637
  from_clause << "\n LEFT OUTER JOIN #{a.table_name} br_t#{idx += 1} "
633
638
  from_clause << if (src_ref = a.source_reflection).macro == :belongs_to
634
- (nm = hmt_assoc.source_reflection.inverse_of&.name)
635
- # binding.pry unless nm
639
+ nm = hmt_assoc.source_reflection.inverse_of&.name
636
640
  link_back << nm
637
641
  "ON br_t#{idx}.id = br_t#{idx - 1}.#{a.foreign_key}"
638
642
  elsif src_ref.options[:as]
639
643
  "ON br_t#{idx}.#{src_ref.type} = '#{src_ref.active_record.name}'" + # "polymorphable_type"
640
644
  " AND br_t#{idx}.#{src_ref.foreign_key} = br_t#{idx - 1}.id"
641
645
  elsif src_ref.options[:source_type]
642
- print "Skipping #{hm.name} --HMT-> #{hm.source_reflection.name} as it uses source_type which is not yet supported"
643
- nix << k
644
- bail_out = true
645
- break
646
- else # Standard has_many
646
+ if a == hm.source_reflection
647
+ print "Skipping #{hm.name} --HMT-> #{hm.source_reflection.name} as it uses source_type in a way which is not yet supported"
648
+ nix << k
649
+ bail_out = true
650
+ break
651
+ # "ON br_t#{idx}.#{a.foreign_type} = '#{src_ref.options[:source_type]}' AND " \
652
+ # "br_t#{idx}.#{a.foreign_key} = br_t#{idx - 1}.id"
653
+ else # Works for HMT through a polymorphic HO
654
+ link_back << hmt_assoc.source_reflection.inverse_of&.name # Some polymorphic "_able" thing
655
+ "ON br_t#{idx - 1}.#{a.foreign_type} = '#{src_ref.options[:source_type]}' AND " \
656
+ "br_t#{idx - 1}.#{a.foreign_key} = br_t#{idx}.id"
657
+ end
658
+ else # Standard has_many or has_one
647
659
  # binding.pry unless (
648
660
  nm = hmt_assoc.source_reflection.inverse_of&.name
649
661
  # )
@@ -706,12 +718,13 @@ module ActiveRecord
706
718
  on_clause << "#{tbl_alias}.#{poly_type} = '#{name}'"
707
719
  end
708
720
  unless from_clause
721
+ tbl_nm = hm.macro == :has_and_belongs_to_many ? hm.join_table : hm.table_name
709
722
  hm_table_name = if is_mysql
710
- "`#{hm.table_name}`"
723
+ "`#{tbl_nm}`"
711
724
  elsif is_postgres || is_mssql
712
- "\"#{(hm.table_name).gsub('.', '"."')}\""
725
+ "\"#{(tbl_nm).gsub('.', '"."')}\""
713
726
  else
714
- hm.table_name
727
+ tbl_nm
715
728
  end
716
729
  end
717
730
  group_bys = ::Brick.is_oracle || is_mssql ? hm_selects : (1..hm_selects.length).to_a
@@ -1390,8 +1403,8 @@ class Object
1390
1403
  # (More information on https://docs.avohq.io/2.0/controllers.html)
1391
1404
  controller_base = Avo::ResourcesController
1392
1405
  end
1393
- table_name = ActiveSupport::Inflector.underscore(plural_class_name)
1394
- singular_table_name = ActiveSupport::Inflector.singularize(table_name)
1406
+ table_name = model&.table_name || ActiveSupport::Inflector.underscore(plural_class_name)
1407
+ singular_table_name = ActiveSupport::Inflector.singularize(ActiveSupport::Inflector.underscore(plural_class_name))
1395
1408
  pk = model&._brick_primary_key(relations.fetch(table_name, nil))
1396
1409
  is_postgres = ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
1397
1410
  is_mysql = ActiveRecord::Base.connection.adapter_name == 'Mysql2'
@@ -1576,7 +1589,6 @@ class Object
1576
1589
  order_by, _ = model._brick_calculate_ordering(ordering, true) # Don't do the txt part
1577
1590
 
1578
1591
  ar_relation = ActiveRecord.version < Gem::Version.new('4') ? model.preload : model.all
1579
-
1580
1592
  @_brick_params = ar_relation.brick_select(params, (selects ||= []), order_by,
1581
1593
  translations = {},
1582
1594
  join_array = ::Brick::JoinArray.new)
@@ -1592,12 +1604,13 @@ class Object
1592
1604
  end
1593
1605
  end
1594
1606
  ar_select = ar_relation.respond_to?(:_select!) ? ar_relation.dup._select!(*selects, *counts) : ar_relation.select(selects + counts)
1595
- instance_variable_set("@#{table_name.pluralize}".to_sym, ar_select)
1596
- if namespace && (idx = lookup_context.prefixes.index(table_name))
1607
+ instance_variable_set("@#{table_name.split('.').last}".to_sym, ar_select)
1608
+ table_name_no_schema = singular_table_name.pluralize
1609
+ if namespace && (idx = lookup_context.prefixes.index(table_name_no_schema))
1597
1610
  lookup_context.prefixes[idx] = "#{namespace.name.underscore}/#{lookup_context.prefixes[idx]}"
1598
1611
  end
1599
1612
  @_brick_excl = session[:_brick_exclude]&.split(',')&.each_with_object([]) do |excl, s|
1600
- if (excl_parts = excl.split('.')).first == table_name
1613
+ if (excl_parts = excl.split('.')).first == table_name_no_schema
1601
1614
  s << excl_parts.last
1602
1615
  end
1603
1616
  end
@@ -1728,7 +1741,12 @@ class Object
1728
1741
  val_part.gsub('^^sl^^', '/')
1729
1742
  end
1730
1743
  end
1731
- model.find(id.is_a?(Array) && id.length == 1 ? id.first : id)
1744
+ # Support friendly_id gem
1745
+ if Object.const_defined?('FriendlyId') && model.instance_variable_get(:@friendly_id_config)
1746
+ model.friendly.find(id.is_a?(Array) && id.length == 1 ? id.first : id)
1747
+ else
1748
+ model.find(id.is_a?(Array) && id.length == 1 ? id.first : id)
1749
+ end
1732
1750
  end
1733
1751
  end
1734
1752
 
@@ -197,7 +197,7 @@ function linkSchemas() {
197
197
  class BrickTitle
198
198
  def initialize(name, view_component)
199
199
  @vc = view_component
200
- @_name = name
200
+ @_name = name || ''
201
201
  end
202
202
  def to_s
203
203
  @_name.html_safe + @vc.instance_variable_get(:@__vc_helpers)&.link_to_brick(nil,
@@ -313,10 +313,10 @@ function linkSchemas() {
313
313
  end
314
314
 
315
315
  if @_brick_model
316
- pk = @_brick_model._brick_primary_key(::Brick.relations.fetch(@_brick_model&.table_name, nil))
316
+ pk = @_brick_model._brick_primary_key(::Brick.relations.fetch((table_name = @_brick_model.table_name.split('.').last), nil))
317
317
  obj_name = model_name.split('::').last.underscore
318
318
  path_obj_name = @_brick_model._brick_index(:singular)
319
- table_name = obj_name.pluralize
319
+ table_name ||= obj_name.pluralize
320
320
  template_link = nil
321
321
  bts, hms = ::Brick.get_bts_and_hms(@_brick_model) # This gets BT and HM and also has_many :through (HMT)
322
322
  hms_columns = [] # Used for 'index'
@@ -346,13 +346,16 @@ function linkSchemas() {
346
346
  end
347
347
  case args.first
348
348
  when 'index'
349
- unless skip_klass_hms.key?(assoc_name.to_sym) || hm_assoc.options[:source]
349
+ if !skip_klass_hms.key?(assoc_name.to_sym) && (
350
+ @_brick_model._br_hm_counts.key?(assoc_name) ||
351
+ @_brick_model._br_bt_descrip.key?(assoc_name) # Will end up here if it's a has_one
352
+ )
350
353
  hm_entry = +"'#{hm_assoc.name}' => [#{assoc_name.inspect}, "
351
- hm_entry << if hm_assoc.macro == :has_many
354
+ hm_entry << if hm_assoc.macro == :has_one
355
+ 'nil'
356
+ else # :has_many or :has_and_belongs_to_many
352
357
  # Postgres column names are limited to 63 characters
353
358
  "'" + "b_r_#{assoc_name}_ct"[0..62] + "'"
354
- else # has_one
355
- 'nil'
356
359
  end
357
360
  hm_entry << ", #{path_keys(hm_assoc, hm_fk_name, pk).inspect}]"
358
361
  hms_columns << hm_entry
@@ -564,10 +567,58 @@ def hide_bcrypt(val, max_len = 200)
564
567
  '(hidden)'
565
568
  else
566
569
  if val.is_a?(String)
567
- val = \"#\{val[0...max_len]}...\" if val.length > max_len
570
+ if (val = val.dup.strip).length > max_len
571
+ if val[0] == '<' # Seems to be HTML?
572
+ cur_len = 0
573
+ cur_idx = 0
574
+ # Find which HTML tags we might be inside so we can apply ending tags to balance
575
+ element_name = nil
576
+ in_closing = nil
577
+ elements = []
578
+ val.each_char do |ch|
579
+ case ch
580
+ when '<'
581
+ element_name = +''
582
+ when '/' # First character of tag is '/'?
583
+ in_closing = true if element_name == ''
584
+ when '>'
585
+ if element_name
586
+ if in_closing
587
+ if (idx = elements.index { |tag| tag.downcase == element_name.downcase })
588
+ elements.delete_at(idx)
589
+ end
590
+ elsif (tag_name = element_name.split.first).present?
591
+ elements.unshift(tag_name)
592
+ end
593
+ element_name = nil
594
+ in_closing = nil
595
+ end
596
+ else
597
+ element_name << ch if element_name
598
+ end
599
+ cur_idx += 1
600
+ # Unless it's inside wickets then this is real text content, and see if we're at the limit
601
+ break if element_name.nil? && ((cur_len += 1) > max_len)
602
+ end
603
+ val = val[0..cur_idx]
604
+ # Somehow still in the middle of an opening tag right at the end? (Should never happen)
605
+ if !in_closing && (tag_name = element_name&.split&.first)&.present?
606
+ elements.unshift(tag_name)
607
+ val << '>'
608
+ end
609
+ elements.each do |closing_tag|
610
+ val << \"</#\{closing_tag}>\"
611
+ end
612
+ else # Not HTML, just cut it at the length
613
+ val = val[0...max_len]
614
+ end
615
+ val = \"#\{val}...\"
616
+ end
568
617
  val = val.dup.force_encoding('UTF-8') unless val.encoding.name == 'UTF-8'
618
+ val
619
+ else
620
+ val.to_s
569
621
  end
570
- val
571
622
  end
572
623
  end
573
624
  def display_value(col_type, val)
@@ -994,8 +1045,12 @@ erDiagram
994
1045
  +"<html>
995
1046
  <head>
996
1047
  #{css}
997
- <title>#{model_name} <%
998
- if (description = (relation = Brick.relations[#{model_name}.table_name])&.fetch(:description, nil)).present?
1048
+ <title><% model = #{model_name}
1049
+ if sub_model = @_brick_params&.fetch(type_col = model.inheritance_column, nil)&.first
1050
+ model = Object.const_get(sub_model.to_sym)
1051
+ end
1052
+ %><%= model.name %><%
1053
+ if (description = (relation = Brick.relations[model.table_name])&.fetch(:description, nil)).present?
999
1054
  %> - <%= description
1000
1055
  %><% end
1001
1056
  %></title>
@@ -1005,15 +1060,15 @@ erDiagram
1005
1060
  #{schema_options}" if schema_options}
1006
1061
  <select id=\"tbl\">#{table_options}</select>
1007
1062
  <table id=\"resourceName\"><tr>
1008
- <td><h1>#{model_name}</h1></td>
1063
+ <td><h1><%= model.name %></h1></td>
1009
1064
  <td id=\"imgErd\" title=\"Show ERD\"></td>
1010
1065
  <% if Object.const_defined?('Avo') && ::Avo.respond_to?(:railtie_namespace) %>
1011
1066
  <td><%= link_to_brick(
1012
1067
  avo_svg,
1013
- { index_proc: Proc.new do |model|
1014
- ::Avo.railtie_routes_url_helpers.send(\"resources_#\{model.base_class.model_name.route_key}_path\".to_sym)
1068
+ { index_proc: Proc.new do |avo_model|
1069
+ ::Avo.railtie_routes_url_helpers.send(\"resources_#\{model.model_name.route_key}_path\".to_sym)
1015
1070
  end,
1016
- title: '#{model_name} in Avo' }
1071
+ title: \"#\{model.name} in Avo\" }
1017
1072
  ) %></td>
1018
1073
  <% end %>
1019
1074
  </tr></table>#{template_link}<%
@@ -1025,13 +1080,13 @@ erDiagram
1025
1080
  <% if @_brick_params.length == 1 # %%% Does not yet work with composite keys
1026
1081
  k, id = @_brick_params.first
1027
1082
  id = id.first if id.is_a?(Array) && id.length == 1
1028
- origin = (key_parts = k.split('.')).length == 1 ? #{model_name} : #{model_name}.reflect_on_association(key_parts.first).klass
1083
+ origin = (key_parts = k.split('.')).length == 1 ? model : model.reflect_on_association(key_parts.first).klass
1029
1084
  if (destination_fk = Brick.relations[origin.table_name][:fks].values.find { |fk| fk[:fk] == key_parts.last }) &&
1030
1085
  (obj = (destination = origin.reflect_on_association(destination_fk[:assoc_name])&.klass)&.find(id)) %>
1031
1086
  <h3>for <%= link_to \"#{"#\{obj.brick_descrip\} (#\{destination.name\})\""}, send(\"#\{destination._brick_index(:singular)\}_path\".to_sym, id) %></h3><%
1032
1087
  end
1033
1088
  end %>
1034
- (<%= link_to 'See all #{model_name.split('::').last.pluralize}', #{@_brick_model._brick_index}_path %>)
1089
+ (<%= link_to \"See all #\{model.base_class.name.split('::').last.pluralize}\", #{@_brick_model._brick_index}_path %>)
1035
1090
  <% end
1036
1091
  # COLUMN EXCLUSIONS
1037
1092
  if @_brick_excl&.present? %>
@@ -1058,10 +1113,10 @@ erDiagram
1058
1113
  end.join(', ')}}
1059
1114
 
1060
1115
  # If the resource is missing, has the user simply created an inappropriately pluralised name for a table?
1061
- @#{table_name} ||= if dym_list = instance_variables.reject do |entry|
1062
- entry.to_s.start_with?('@_') ||
1063
- ['@cache_hit', '@marked_for_same_origin_verification', '@view_renderer', '@view_flow', '@output_buffer', '@virtual_path'].include?(entry.to_s)
1064
- end
1116
+ @#{table_name} ||= if (dym_list = instance_variables.reject do |entry|
1117
+ entry.to_s.start_with?('@_') ||
1118
+ ['@cache_hit', '@marked_for_same_origin_verification', '@view_renderer', '@view_flow', '@output_buffer', '@virtual_path'].include?(entry.to_s)
1119
+ end).present?
1065
1120
  msg = \"Can't find resource \\\"#{table_name}\\\".\"
1066
1121
  # Can't be sure otherwise of what is up, so check DidYouMean and offer a suggestion.
1067
1122
  if (dym = DidYouMean::SpellChecker.new(dictionary: dym_list).correct('@#{table_name}')).present?
@@ -1078,7 +1133,7 @@ erDiagram
1078
1133
 
1079
1134
  # Write out the mega-grid
1080
1135
  brick_grid(@#{table_name}, @_brick_bt_descrip, @_brick_sequence, @_brick_incl, @_brick_excl,
1081
- cols, poly_cols, bts, #{hms_keys.inspect}, {#{hms_columns.join(', ')}}) %>
1136
+ cols, poly_cols, bts, #{hms_keys.inspect}, {#{hms_columns.join(', ')}}) %>
1082
1137
 
1083
1138
  #{"<hr><%= link_to \"New #{obj_name}\", new_#{path_obj_name}_path %>" unless @_brick_model.is_view?}
1084
1139
  #{script}
@@ -11,7 +11,7 @@ module Brick::Rails::FormTags
11
11
  out << "<th x-order=\"#{pk.join(',')}\"></th>"
12
12
  end
13
13
 
14
- col_keys ||= relation.columns.each_with_object([]) do |col, s|
14
+ col_keys = relation.columns.each_with_object([]) do |col, s|
15
15
  col_name = col.name
16
16
  next if inclusions&.exclude?(col_name) ||
17
17
  (pk.include?(col_name) && [:integer, :uuid].include?(col.type) && !bts.key?(col_name)) ||
@@ -39,8 +39,10 @@ module Brick::Rails::FormTags
39
39
  "#{' x-order="' + col_name + '"' if true}>#{col_name}"
40
40
  end
41
41
  elsif col # HM column
42
+ options = {}
43
+ options[col[1].inheritance_column] = col[1].name unless col[1] == col[1].base_class
42
44
  s << "<th#{' x-order="' + col_name + '"' if true}>#{col[2]} "
43
- s << (col.first ? "#{col[3]}" : "#{link_to(col[3], send("#{col[1]._brick_index}_path"))}")
45
+ s << (col.first ? "#{col[3]}" : "#{link_to(col[3], send("#{col[1]._brick_index}_path", options))}")
44
46
  elsif cust_cols.key?(col_name) # Custom column
45
47
  s << "<th x-order=\"#{col_name}\">#{col_name}"
46
48
  elsif col_name.is_a?(Symbol) && (hot = bts[col_name]) # has_one :through
@@ -96,17 +98,17 @@ module Brick::Rails::FormTags
96
98
  if hms_col.length == 1
97
99
  out << hms_col.first
98
100
  else
99
- klass = (col = cols[col_name])[1]
101
+ hm_klass = (col = cols[col_name])[1]
100
102
  if col[2] == 'HO'
101
- descrips = bt_descrip[col_name.to_sym][klass]
103
+ descrips = bt_descrip[col_name.to_sym][hm_klass]
102
104
  if (ho_id = (ho_id_col = descrips.last).map { |id_col| obj.send(id_col.to_sym) })&.first
103
- ho_txt = klass.brick_descrip(obj, descrips[0..-2].map { |id| obj.send(id.last[0..62]) }, ho_id_col)
104
- out << link_to(ho_txt, send("#{klass.base_class._brick_index(:singular)}_path".to_sym, ho_id))
105
+ ho_txt = hm_klass.brick_descrip(obj, descrips[0..-2].map { |id| obj.send(id.last[0..62]) }, ho_id_col)
106
+ out << link_to(ho_txt, send("#{hm_klass.base_class._brick_index(:singular)}_path".to_sym, ho_id))
105
107
  end
106
108
  else
107
109
  if (ct = obj.send(hms_col[1].to_sym)&.to_i)&.positive?
108
110
  out << "#{link_to("#{ct || 'View'} #{hms_col.first}",
109
- send("#{klass._brick_index}_path".to_sym,
111
+ send("#{hm_klass._brick_index}_path".to_sym,
110
112
  hms_col[2].each_with_object({}) { |v, s| s[v.first] = v.last.is_a?(String) ? v.last : obj.send(v.last) })
111
113
  )}\n"
112
114
  end
@@ -5,7 +5,7 @@ module Brick
5
5
  module VERSION
6
6
  MAJOR = 1
7
7
  MINOR = 0
8
- TINY = 100
8
+ TINY = 101
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
@@ -640,50 +640,62 @@ In config/initializers/brick.rb appropriate entries would look something like:
640
640
  table_class_length = 38 # Length of "Classes that can be built from tables:"
641
641
  view_class_length = 37 # Length of "Classes that can be built from views:"
642
642
 
643
- brick_routes_create = lambda do |schema_name, controller_name, v, options|
643
+ brick_routes_create = lambda do |schema_name, res_name, options|
644
644
  if schema_name # && !Object.const_defined('Apartment')
645
645
  send(:namespace, schema_name) do
646
- send(:resources, v[:resource].to_sym, **options)
646
+ send(:resources, res_name.to_sym, **options)
647
647
  end
648
648
  else
649
- send(:resources, v[:resource].to_sym, **options)
649
+ send(:resources, res_name.to_sym, **options)
650
650
  end
651
651
  end
652
652
 
653
653
  # %%% TODO: If no auto-controllers then enumerate the controllers folder in order to build matching routes
654
654
  # If auto-controllers and auto-models are both enabled then this makes sense:
655
655
  controller_prefix = (path_prefix ? "#{path_prefix}/" : '')
656
+ sti_subclasses = ::Brick.config.sti_namespace_prefixes.each_with_object(Hash.new { |h, k| h[k] = [] }) do |v, s|
657
+ # Turn something like {"::Spouse"=>"Person", "::Friend"=>"Person"} into {"Person"=>["Spouse", "Friend"]}
658
+ s[v.last] << v.first[2..-1] unless v.first.end_with?('::')
659
+ end
656
660
  ::Brick.relations.each do |k, v|
657
- unless !(controller_name = v.fetch(:resource, nil)&.pluralize) || existing_controllers.key?(controller_name)
658
- options = {}
659
- options[:only] = [:index, :show] if v.key?(:isView)
660
- # First do the API routes
661
- full_resource = nil
662
- if (schema_name = v.fetch(:schema, nil))
663
- full_resource = "#{schema_name}/#{v[:resource]}"
664
- send(:get, "#{::Brick.api_root}#{full_resource}", { to: "#{controller_prefix}#{schema_name}/#{controller_name}#index" }) if Object.const_defined?('Rswag::Ui')
661
+ next if !(controller_name = v.fetch(:resource, nil)&.pluralize) || existing_controllers.key?(controller_name)
662
+
663
+ options = {}
664
+ options[:only] = [:index, :show] if v.key?(:isView)
665
+ # First do the API routes
666
+ full_resource = nil
667
+ if (schema_name = v.fetch(:schema, nil))
668
+ full_resource = "#{schema_name}/#{v[:resource]}"
669
+ send(:get, "#{::Brick.api_root}#{full_resource}", { to: "#{controller_prefix}#{schema_name}/#{controller_name}#index" }) if Object.const_defined?('Rswag::Ui')
670
+ else
671
+ # Normally goes to something like: /api/v1/employees
672
+ send(:get, "#{::Brick.api_root}#{v[:resource]}", { to: "#{controller_prefix}#{controller_name}#index" }) if Object.const_defined?('Rswag::Ui')
673
+ end
674
+
675
+ # Track routes being built
676
+ if (class_name = v.fetch(:class_name, nil))
677
+ if v.key?(:isView)
678
+ view_class_length = class_name.length if class_name.length > view_class_length
679
+ views
665
680
  else
666
- # Normally goes to something like: /api/v1/employees
667
- send(:get, "#{::Brick.api_root}#{v[:resource]}", { to: "#{controller_prefix}#{controller_name}#index" }) if Object.const_defined?('Rswag::Ui')
668
- end
669
- # Now the normal routes
670
- if path_prefix
671
- # Was: send(:scope, path: path_prefix) do
672
- send(:namespace, path_prefix) do
673
- brick_routes_create.call(schema_name, controller_name, v, options)
681
+ table_class_length = class_name.length if class_name.length > table_class_length
682
+ tables
683
+ end << [class_name, full_resource || v[:resource]]
684
+ end
685
+
686
+ # Now the normal routes
687
+ if path_prefix
688
+ # Was: send(:scope, path: path_prefix) do
689
+ send(:namespace, path_prefix) do
690
+ brick_routes_create.call(schema_name, v[:resource], options)
691
+ sti_subclasses.fetch(class_name, nil)&.each do |sc| # Add any STI subclass routes for this relation
692
+ brick_routes_create.call(schema_name, sc.underscore.tr('/', '_').pluralize, options)
674
693
  end
675
- else
676
- brick_routes_create.call(schema_name, controller_name, v, options)
677
694
  end
678
-
679
- if (class_name = v.fetch(:class_name, nil))
680
- if v.key?(:isView)
681
- view_class_length = class_name.length if class_name.length > view_class_length
682
- views
683
- else
684
- table_class_length = class_name.length if class_name.length > table_class_length
685
- tables
686
- end << [class_name, full_resource || v[:resource]]
695
+ else
696
+ brick_routes_create.call(schema_name, v[:resource], options)
697
+ sti_subclasses.fetch(class_name, nil)&.each do |sc| # Add any STI subclass routes for this relation
698
+ brick_routes_create.call(schema_name, sc.underscore.tr('/', '_').pluralize, options)
687
699
  end
688
700
  end
689
701
  end
@@ -1322,24 +1334,26 @@ module ActiveRecord
1322
1334
  private
1323
1335
 
1324
1336
  # %%% Pretty much have to flat-out replace this guy (I think anyway)
1325
- # Good with Rails 5.24 and 7 on this
1326
- def build(associations, base_klass, root = nil, path = '')
1327
- root ||= associations
1328
- associations.map do |name, right|
1329
- reflection = find_reflection base_klass, name
1330
- reflection.check_validity!
1331
- reflection.check_eager_loadable!
1332
-
1333
- if reflection.polymorphic?
1334
- raise EagerLoadPolymorphicError.new(reflection)
1335
- end
1337
+ # Good with Rails 5.24 through 7 on this
1338
+ # Ransack gem includes Polyamorous which replaces #build in a different way (which we handle below)
1339
+ unless Gem::Specification.all_names.any? { |g| g.start_with?('ransack-') }
1340
+ def build(associations, base_klass, root = nil, path = '')
1341
+ root ||= associations
1342
+ associations.map do |name, right|
1343
+ reflection = find_reflection base_klass, name
1344
+ reflection.check_validity!
1345
+ reflection.check_eager_loadable!
1346
+
1347
+ if reflection.polymorphic?
1348
+ raise EagerLoadPolymorphicError.new(reflection)
1349
+ end
1336
1350
 
1337
- # %%% The path
1338
- link_path = path.blank? ? name.to_s : path + ".#{name}"
1339
- ja = JoinAssociation.new(reflection, build(right, reflection.klass, root, link_path))
1340
- ja.instance_variable_set(:@link_path, link_path) # Make note on the JoinAssociation of its AR path
1341
- ja.instance_variable_set(:@assocs, root)
1342
- ja
1351
+ link_path = path.blank? ? name.to_s : path + ".#{name}"
1352
+ ja = JoinAssociation.new(reflection, build(right, reflection.klass, root, link_path))
1353
+ ja.instance_variable_set(:@link_path, link_path) # Make note on the JoinAssociation of its AR path
1354
+ ja.instance_variable_set(:@assocs, root)
1355
+ ja
1356
+ end
1343
1357
  end
1344
1358
  end
1345
1359
 
@@ -1348,10 +1362,9 @@ module ActiveRecord
1348
1362
  alias _brick_table_aliases_for table_aliases_for
1349
1363
  def table_aliases_for(parent, node)
1350
1364
  result = _brick_table_aliases_for(parent, node)
1351
-
1352
1365
  # Capture the table alias name that was chosen
1353
- link_path = node.instance_variable_get(:@link_path)
1354
1366
  if (relation = node.instance_variable_get(:@assocs)&.instance_variable_get(:@relation))
1367
+ link_path = node.instance_variable_get(:@link_path)
1355
1368
  relation.brick_links[link_path] = result.first.table_alias || result.first.table_name
1356
1369
  end
1357
1370
  result
@@ -1360,11 +1373,14 @@ module ActiveRecord
1360
1373
  alias _brick_make_constraints make_constraints
1361
1374
  def make_constraints(parent, child, join_type)
1362
1375
  result = _brick_make_constraints(parent, child, join_type)
1363
-
1364
1376
  # Capture the table alias name that was chosen
1365
- link_path = child.instance_variable_get(:@link_path)
1366
1377
  if (relation = child.instance_variable_get(:@assocs)&.instance_variable_get(:@relation))
1367
- relation.brick_links[link_path] = result.first.left.table_alias || result.first.left.table_name
1378
+ link_path = child.instance_variable_get(:@link_path)
1379
+ relation.brick_links[link_path] = if child.table.is_a?(Arel::Nodes::TableAlias)
1380
+ child.table.right
1381
+ else
1382
+ result.first&.left&.table_alias || child.table_name
1383
+ end
1368
1384
  end
1369
1385
  result
1370
1386
  end
@@ -1374,4 +1390,47 @@ module ActiveRecord
1374
1390
  end
1375
1391
  end
1376
1392
 
1393
+ # Now the Ransack Polyamorous version of #build
1394
+ if Gem::Specification.all_names.any? { |g| g.start_with?('ransack-') }
1395
+ require "polyamorous/activerecord_#{::ActiveRecord::VERSION::STRING[0, 3]}_ruby_2/join_dependency"
1396
+ module Polyamorous::JoinDependencyExtensions
1397
+ def build(associations, base_klass, root = nil, path = '')
1398
+ root ||= associations
1399
+ puts associations.map(&:first)
1400
+
1401
+ associations.map do |name, right|
1402
+ link_path = path.blank? ? name.to_s : path + ".#{name}"
1403
+ ja = if name.is_a? ::Polyamorous::Join
1404
+ reflection = find_reflection base_klass, name.name
1405
+ reflection.check_validity!
1406
+ reflection.check_eager_loadable!
1407
+
1408
+ klass = if reflection.polymorphic?
1409
+ name.klass || base_klass
1410
+ else
1411
+ reflection.klass
1412
+ end
1413
+ ::ActiveRecord::Associations::JoinDependency::JoinAssociation.new(
1414
+ reflection, build(right, klass, root, link_path), name.klass, name.type
1415
+ )
1416
+ else
1417
+ reflection = find_reflection base_klass, name
1418
+ reflection.check_validity!
1419
+ reflection.check_eager_loadable!
1420
+
1421
+ if reflection.polymorphic?
1422
+ raise ActiveRecord::EagerLoadPolymorphicError.new(reflection)
1423
+ end
1424
+ ::ActiveRecord::Associations::JoinDependency::JoinAssociation.new(
1425
+ reflection, build(right, reflection.klass, root, link_path)
1426
+ )
1427
+ end
1428
+ ja.instance_variable_set(:@link_path, link_path) # Make note on the JoinAssociation of its AR path
1429
+ ja.instance_variable_set(:@assocs, root)
1430
+ ja
1431
+ end
1432
+ end
1433
+ end
1434
+ end
1435
+
1377
1436
  require 'brick/extensions'
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.100
4
+ version: 1.0.101
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-12-09 00:00:00.000000000 Z
11
+ date: 2022-12-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord