brick 1.0.100 → 1.0.101

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 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