brick 1.0.99 → 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 +4 -4
- data/lib/brick/extensions.rb +43 -46
- data/lib/brick/frameworks/rails/engine.rb +79 -40
- data/lib/brick/frameworks/rails/form_tags.rb +12 -54
- data/lib/brick/version_number.rb +1 -1
- data/lib/brick.rb +111 -52
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eba38d653370b0cc3e98f2adc82d8c475854440745bd35caab9a9a4253fc152c
|
4
|
+
data.tar.gz: 18ca517b90266cf5db711040a7f40c8e848600135ef0a39ad91da9cd2a0b1c89
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 859f48999fb0e8d1010a701e29c9f0275f716b20f54b4348576f4dbff7f68da1eb83709a51a1a7acd7debaf4dc1f82e863048ef16cda6b5f59862246e0c50787
|
7
|
+
data.tar.gz: d93c3db79715f62705c0b8f2f5bd2640a2756e1fbcb6aa6a7cf017a18bc31fa5e98496ea41539611c149f84870f24596c105d146484519b7f040d2f36b25ce45
|
data/lib/brick/extensions.rb
CHANGED
@@ -404,21 +404,9 @@ module ActiveRecord
|
|
404
404
|
def brick_select(params, selects = [], order_by = nil, translations = {}, join_array = ::Brick::JoinArray.new)
|
405
405
|
is_add_bts = is_add_hms = true
|
406
406
|
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
model._brick_calculate_bts_hms(translations, join_array) if is_add_bts || is_add_hms
|
411
|
-
else
|
412
|
-
is_api = true
|
413
|
-
# If there are any provided selects, treat them as API columns and build them as cust_cols since they
|
414
|
-
# can be built using DSL.
|
415
|
-
# false = not polymorphic, and true = yes -- please emit_dsl
|
416
|
-
selects.each do |api_col|
|
417
|
-
pieces, my_dsl = brick_parse_dsl(join_array, [], translations, false, "[#{api_col}]", true)
|
418
|
-
_br_cust_cols[api_col.tr('.', '_')] = [pieces, my_dsl]
|
419
|
-
end
|
420
|
-
selects.clear # Now these have become custom columns
|
421
|
-
end
|
407
|
+
# Build out cust_cols, bt_descrip and hm_counts now so that they are available on the
|
408
|
+
# model early in case the user wants to do an ORDER BY based on any of that.
|
409
|
+
model._brick_calculate_bts_hms(translations, join_array) if is_add_bts || is_add_hms
|
422
410
|
|
423
411
|
is_postgres = ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
|
424
412
|
is_mysql = ActiveRecord::Base.connection.adapter_name == 'Mysql2'
|
@@ -426,7 +414,7 @@ module ActiveRecord
|
|
426
414
|
is_distinct = nil
|
427
415
|
wheres = {}
|
428
416
|
params.each do |k, v|
|
429
|
-
next if ['_brick_schema', '_brick_order', '
|
417
|
+
next if ['_brick_schema', '_brick_order', 'controller', 'action'].include?(k)
|
430
418
|
|
431
419
|
if (where_col = (ks = k.split('.')).last)[-1] == '!'
|
432
420
|
where_col = where_col[0..-2]
|
@@ -454,14 +442,17 @@ module ActiveRecord
|
|
454
442
|
# ActiveRecord::StatementInvalid (TinyTds::Error: DBPROCESS is dead or not enabled)
|
455
443
|
# Relevant info here: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/issues/402
|
456
444
|
columns.each do |col|
|
457
|
-
next if is_api && id_parts.exclude?(col.name) # Only keep the ID columns if this is an API request
|
458
|
-
|
459
445
|
col_alias = " AS #{col.name}_" if (col_name = col.name) == 'class'
|
460
446
|
selects << if is_mysql
|
461
447
|
"`#{tbl_no_schema}`.`#{col_name}`#{col_alias}"
|
462
448
|
elsif is_postgres || is_mssql
|
463
|
-
# Postgres can not use DISTINCT with any columns that are XML
|
464
|
-
|
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
|
465
456
|
"\"#{tbl_no_schema}\".\"#{col_name}\"#{cast_as_text}#{col_alias}"
|
466
457
|
elsif col.type # Could be Sqlite or Oracle
|
467
458
|
if col_alias || !(/^[a-z0-9_]+$/ =~ col_name)
|
@@ -505,6 +496,7 @@ module ActiveRecord
|
|
505
496
|
# binding.pry
|
506
497
|
next
|
507
498
|
end
|
499
|
+
|
508
500
|
key_klass = nil
|
509
501
|
key_tbl_name = nil
|
510
502
|
dest_pk = nil
|
@@ -644,19 +636,26 @@ module ActiveRecord
|
|
644
636
|
through_sources.map do |a|
|
645
637
|
from_clause << "\n LEFT OUTER JOIN #{a.table_name} br_t#{idx += 1} "
|
646
638
|
from_clause << if (src_ref = a.source_reflection).macro == :belongs_to
|
647
|
-
|
648
|
-
# binding.pry unless nm
|
639
|
+
nm = hmt_assoc.source_reflection.inverse_of&.name
|
649
640
|
link_back << nm
|
650
641
|
"ON br_t#{idx}.id = br_t#{idx - 1}.#{a.foreign_key}"
|
651
642
|
elsif src_ref.options[:as]
|
652
643
|
"ON br_t#{idx}.#{src_ref.type} = '#{src_ref.active_record.name}'" + # "polymorphable_type"
|
653
644
|
" AND br_t#{idx}.#{src_ref.foreign_key} = br_t#{idx - 1}.id"
|
654
645
|
elsif src_ref.options[:source_type]
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
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
|
660
659
|
# binding.pry unless (
|
661
660
|
nm = hmt_assoc.source_reflection.inverse_of&.name
|
662
661
|
# )
|
@@ -719,12 +718,13 @@ module ActiveRecord
|
|
719
718
|
on_clause << "#{tbl_alias}.#{poly_type} = '#{name}'"
|
720
719
|
end
|
721
720
|
unless from_clause
|
721
|
+
tbl_nm = hm.macro == :has_and_belongs_to_many ? hm.join_table : hm.table_name
|
722
722
|
hm_table_name = if is_mysql
|
723
|
-
"`#{
|
723
|
+
"`#{tbl_nm}`"
|
724
724
|
elsif is_postgres || is_mssql
|
725
|
-
"\"#{(
|
725
|
+
"\"#{(tbl_nm).gsub('.', '"."')}\""
|
726
726
|
else
|
727
|
-
|
727
|
+
tbl_nm
|
728
728
|
end
|
729
729
|
end
|
730
730
|
group_bys = ::Brick.is_oracle || is_mssql ? hm_selects : (1..hm_selects.length).to_a
|
@@ -984,7 +984,7 @@ Module.class_exec do
|
|
984
984
|
::Brick.is_oracle ? class_name.upcase : class_name,
|
985
985
|
(plural_class_name = class_name.pluralize)].find { |s| Brick.db_schemas&.include?(s) }&.camelize ||
|
986
986
|
(::Brick.config.sti_namespace_prefixes&.key?("::#{class_name}::") && class_name) ||
|
987
|
-
(::Brick.config.table_name_prefixes
|
987
|
+
(::Brick.config.table_name_prefixes.values.include?(class_name) && class_name))
|
988
988
|
return self.const_get(schema_name) if self.const_defined?(schema_name)
|
989
989
|
|
990
990
|
# Build out a module for the schema if it's namespaced
|
@@ -1403,8 +1403,8 @@ class Object
|
|
1403
1403
|
# (More information on https://docs.avohq.io/2.0/controllers.html)
|
1404
1404
|
controller_base = Avo::ResourcesController
|
1405
1405
|
end
|
1406
|
-
table_name = ActiveSupport::Inflector.underscore(plural_class_name)
|
1407
|
-
singular_table_name = ActiveSupport::Inflector.singularize(
|
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))
|
1408
1408
|
pk = model&._brick_primary_key(relations.fetch(table_name, nil))
|
1409
1409
|
is_postgres = ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
|
1410
1410
|
is_mysql = ActiveRecord::Base.connection.adapter_name == 'Mysql2'
|
@@ -1589,14 +1589,6 @@ class Object
|
|
1589
1589
|
order_by, _ = model._brick_calculate_ordering(ordering, true) # Don't do the txt part
|
1590
1590
|
|
1591
1591
|
ar_relation = ActiveRecord.version < Gem::Version.new('4') ? model.preload : model.all
|
1592
|
-
|
1593
|
-
if (cc = params['_brick_api']&.split(','))
|
1594
|
-
is_api = true
|
1595
|
-
selects = cc
|
1596
|
-
counts = [] # No need for any extra HM count columns
|
1597
|
-
model._br_cust_cols.clear
|
1598
|
-
end
|
1599
|
-
|
1600
1592
|
@_brick_params = ar_relation.brick_select(params, (selects ||= []), order_by,
|
1601
1593
|
translations = {},
|
1602
1594
|
join_array = ::Brick::JoinArray.new)
|
@@ -1611,14 +1603,14 @@ class Object
|
|
1611
1603
|
"b_r_#{v.first}.c_t_ AS \"b_r_#{v.first}_ct\""
|
1612
1604
|
end
|
1613
1605
|
end
|
1614
|
-
|
1615
1606
|
ar_select = ar_relation.respond_to?(:_select!) ? ar_relation.dup._select!(*selects, *counts) : ar_relation.select(selects + counts)
|
1616
|
-
instance_variable_set("@#{table_name.
|
1617
|
-
|
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))
|
1618
1610
|
lookup_context.prefixes[idx] = "#{namespace.name.underscore}/#{lookup_context.prefixes[idx]}"
|
1619
1611
|
end
|
1620
1612
|
@_brick_excl = session[:_brick_exclude]&.split(',')&.each_with_object([]) do |excl, s|
|
1621
|
-
if (excl_parts = excl.split('.')).first ==
|
1613
|
+
if (excl_parts = excl.split('.')).first == table_name_no_schema
|
1622
1614
|
s << excl_parts.last
|
1623
1615
|
end
|
1624
1616
|
end
|
@@ -1749,7 +1741,12 @@ class Object
|
|
1749
1741
|
val_part.gsub('^^sl^^', '/')
|
1750
1742
|
end
|
1751
1743
|
end
|
1752
|
-
|
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
|
1753
1750
|
end
|
1754
1751
|
end
|
1755
1752
|
|
@@ -54,7 +54,7 @@ module Brick
|
|
54
54
|
end
|
55
55
|
|
56
56
|
# When table names have specific prefixes, automatically place them in their own module with a table_name_prefix.
|
57
|
-
::Brick.table_name_prefixes = app.config.brick.fetch(:table_name_prefixes,
|
57
|
+
::Brick.table_name_prefixes = app.config.brick.fetch(:table_name_prefixes, {})
|
58
58
|
|
59
59
|
# Columns to treat as being metadata for purposes of identifying associative tables for has_many :through
|
60
60
|
::Brick.metadata_columns = app.config.brick.fetch(:metadata_columns, ['created_at', 'updated_at', 'deleted_at'])
|
@@ -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
|
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
|
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
|
-
|
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 == :
|
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
|
@@ -424,14 +427,6 @@ h1, h3 {
|
|
424
427
|
cursor: pointer;
|
425
428
|
}
|
426
429
|
|
427
|
-
#apiToggle {
|
428
|
-
border: 2px solid purple;
|
429
|
-
}
|
430
|
-
|
431
|
-
#apiToggle, .apiColName {
|
432
|
-
cursor: pointer;
|
433
|
-
}
|
434
|
-
|
435
430
|
#dropper {
|
436
431
|
background-color: #eee;
|
437
432
|
}
|
@@ -572,10 +567,58 @@ def hide_bcrypt(val, max_len = 200)
|
|
572
567
|
'(hidden)'
|
573
568
|
else
|
574
569
|
if val.is_a?(String)
|
575
|
-
val =
|
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
|
576
617
|
val = val.dup.force_encoding('UTF-8') unless val.encoding.name == 'UTF-8'
|
618
|
+
val
|
619
|
+
else
|
620
|
+
val.to_s
|
577
621
|
end
|
578
|
-
val
|
579
622
|
end
|
580
623
|
end
|
581
624
|
def display_value(col_type, val)
|
@@ -1002,8 +1045,12 @@ erDiagram
|
|
1002
1045
|
+"<html>
|
1003
1046
|
<head>
|
1004
1047
|
#{css}
|
1005
|
-
<title
|
1006
|
-
|
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?
|
1007
1054
|
%> - <%= description
|
1008
1055
|
%><% end
|
1009
1056
|
%></title>
|
@@ -1012,19 +1059,16 @@ erDiagram
|
|
1012
1059
|
<p style=\"color: green\"><%= notice %></p>#{"
|
1013
1060
|
#{schema_options}" if schema_options}
|
1014
1061
|
<select id=\"tbl\">#{table_options}</select>
|
1015
|
-
|
1016
|
-
<%= pick_api(#{model_name}).html_safe %>
|
1017
|
-
|
1018
1062
|
<table id=\"resourceName\"><tr>
|
1019
|
-
<td><h1
|
1063
|
+
<td><h1><%= model.name %></h1></td>
|
1020
1064
|
<td id=\"imgErd\" title=\"Show ERD\"></td>
|
1021
1065
|
<% if Object.const_defined?('Avo') && ::Avo.respond_to?(:railtie_namespace) %>
|
1022
1066
|
<td><%= link_to_brick(
|
1023
1067
|
avo_svg,
|
1024
|
-
{ index_proc: Proc.new do |
|
1025
|
-
::Avo.railtie_routes_url_helpers.send(\"resources_#\{model.
|
1068
|
+
{ index_proc: Proc.new do |avo_model|
|
1069
|
+
::Avo.railtie_routes_url_helpers.send(\"resources_#\{model.model_name.route_key}_path\".to_sym)
|
1026
1070
|
end,
|
1027
|
-
title:
|
1071
|
+
title: \"#\{model.name} in Avo\" }
|
1028
1072
|
) %></td>
|
1029
1073
|
<% end %>
|
1030
1074
|
</tr></table>#{template_link}<%
|
@@ -1036,13 +1080,13 @@ erDiagram
|
|
1036
1080
|
<% if @_brick_params.length == 1 # %%% Does not yet work with composite keys
|
1037
1081
|
k, id = @_brick_params.first
|
1038
1082
|
id = id.first if id.is_a?(Array) && id.length == 1
|
1039
|
-
origin = (key_parts = k.split('.')).length == 1 ?
|
1083
|
+
origin = (key_parts = k.split('.')).length == 1 ? model : model.reflect_on_association(key_parts.first).klass
|
1040
1084
|
if (destination_fk = Brick.relations[origin.table_name][:fks].values.find { |fk| fk[:fk] == key_parts.last }) &&
|
1041
1085
|
(obj = (destination = origin.reflect_on_association(destination_fk[:assoc_name])&.klass)&.find(id)) %>
|
1042
1086
|
<h3>for <%= link_to \"#{"#\{obj.brick_descrip\} (#\{destination.name\})\""}, send(\"#\{destination._brick_index(:singular)\}_path\".to_sym, id) %></h3><%
|
1043
1087
|
end
|
1044
1088
|
end %>
|
1045
|
-
(<%= link_to
|
1089
|
+
(<%= link_to \"See all #\{model.base_class.name.split('::').last.pluralize}\", #{@_brick_model._brick_index}_path %>)
|
1046
1090
|
<% end
|
1047
1091
|
# COLUMN EXCLUSIONS
|
1048
1092
|
if @_brick_excl&.present? %>
|
@@ -1069,10 +1113,10 @@ erDiagram
|
|
1069
1113
|
end.join(', ')}}
|
1070
1114
|
|
1071
1115
|
# If the resource is missing, has the user simply created an inappropriately pluralised name for a table?
|
1072
|
-
@#{table_name} ||= if dym_list = instance_variables.reject do |entry|
|
1073
|
-
|
1074
|
-
|
1075
|
-
|
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?
|
1076
1120
|
msg = \"Can't find resource \\\"#{table_name}\\\".\"
|
1077
1121
|
# Can't be sure otherwise of what is up, so check DidYouMean and offer a suggestion.
|
1078
1122
|
if (dym = DidYouMean::SpellChecker.new(dictionary: dym_list).correct('@#{table_name}')).present?
|
@@ -1088,13 +1132,8 @@ erDiagram
|
|
1088
1132
|
end
|
1089
1133
|
|
1090
1134
|
# Write out the mega-grid
|
1091
|
-
|
1092
|
-
|
1093
|
-
cols, poly_cols, {}, [], {})
|
1094
|
-
else
|
1095
|
-
brick_grid(@#{table_name}, @_brick_bt_descrip, @_brick_sequence, @_brick_incl, @_brick_excl,
|
1096
|
-
cols, poly_cols, bts, #{hms_keys.inspect}, {#{hms_columns.join(', ')}})
|
1097
|
-
end %>
|
1135
|
+
brick_grid(@#{table_name}, @_brick_bt_descrip, @_brick_sequence, @_brick_incl, @_brick_excl,
|
1136
|
+
cols, poly_cols, bts, #{hms_keys.inspect}, {#{hms_columns.join(', ')}}) %>
|
1098
1137
|
|
1099
1138
|
#{"<hr><%= link_to \"New #{obj_name}\", new_#{path_obj_name}_path %>" unless @_brick_model.is_view?}
|
1100
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
|
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
|
-
|
101
|
+
hm_klass = (col = cols[col_name])[1]
|
100
102
|
if col[2] == 'HO'
|
101
|
-
descrips = bt_descrip[col_name.to_sym][
|
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 =
|
104
|
-
out << link_to(ho_txt, send("#{
|
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("#{
|
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
|
@@ -137,51 +139,6 @@ module Brick::Rails::FormTags
|
|
137
139
|
out.html_safe
|
138
140
|
end # brick_grid
|
139
141
|
|
140
|
-
# Recursively render UL and LI to choose columns to include
|
141
|
-
def pick_api(model, is_last = nil, visited = [])
|
142
|
-
out = +''
|
143
|
-
if visited.empty?
|
144
|
-
out << '<span id="apiToggle">API buffet</span><div id="apiBuffet" style="display: none;">'
|
145
|
-
out << '<textarea id="apiCode" cols="100"></textarea>'
|
146
|
-
out << '<input type="button" id="apiRender" value="Render">'
|
147
|
-
end
|
148
|
-
out << "\n#{indent = ' ' * visited.length}<ul>"
|
149
|
-
model.column_names.each { |col_name| out << "\n#{indent} <li class=\"apiColName\" x-nm=\"#{visited.map { |v| "#{v.last}." }.join}#{col_name}\">#{col_name}</li>" }
|
150
|
-
unless is_last || visited.length == 2
|
151
|
-
model.reflect_on_all_associations.each_with_object({}) do |v, s|
|
152
|
-
next if v.macro == :has_many || v.polymorphic?
|
153
|
-
|
154
|
-
out << "\n#{indent} <li><b>#{v.name}</b>#{pick_api(v.klass, visited.map(&:first).include?(v.klass),
|
155
|
-
visited.dup << [v.klass, v.name]
|
156
|
-
)}"
|
157
|
-
out << "\n#{indent} </li>"
|
158
|
-
s[v.name] = nil
|
159
|
-
end
|
160
|
-
end
|
161
|
-
out << "\n#{indent}</ul>"
|
162
|
-
if visited.empty?
|
163
|
-
out << '</div><script>[... document.getElementsByClassName("apiColName")].forEach(function (li) {li.addEventListener("click", apiColClick);});'
|
164
|
-
out << "
|
165
|
-
var colList = [];
|
166
|
-
var apiBuffet = document.getElementById(\"apiBuffet\");
|
167
|
-
var apiCode = document.getElementById(\"apiCode\");
|
168
|
-
function apiColClick(evt) {
|
169
|
-
apiCode.innerHTML += this.getAttribute(\"x-nm\") + \",\\n\";
|
170
|
-
}
|
171
|
-
document.getElementById(\"apiToggle\").addEventListener(\"click\", function () {
|
172
|
-
apiBuffet.style.display = (apiBuffet.style.display === \"block\" ? \"none\" : \"block\");
|
173
|
-
});
|
174
|
-
// Cheap and cheerful way to render a list of columns just for the demo
|
175
|
-
document.getElementById(\"apiRender\").addEventListener(\"click\", function () {
|
176
|
-
var changecolList = apiCode.innerHTML.substring(0, apiCode.innerHTML.length - 2);
|
177
|
-
location.href = changeout(location.href, \"_brick_api\", changecolList);
|
178
|
-
});
|
179
|
-
</script>
|
180
|
-
"
|
181
|
-
end
|
182
|
-
out
|
183
|
-
end
|
184
|
-
|
185
142
|
def link_to_brick(*args, **kwargs)
|
186
143
|
return unless ::Brick.config.mode == :on
|
187
144
|
|
@@ -231,13 +188,14 @@ document.getElementById(\"apiRender\").addEventListener(\"click\", function () {
|
|
231
188
|
end
|
232
189
|
end
|
233
190
|
filter = "?#{filter_parts.join('&')}" if filter_parts.present?
|
191
|
+
app_routes = Rails.application.routes # In case we're operating in another engine, reference the application since Brick routes are placed there.
|
234
192
|
if (klass_or_obj&.is_a?(Class) && klass_or_obj < ActiveRecord::Base) ||
|
235
193
|
(klass_or_obj&.is_a?(ActiveRecord::Base) && klass_or_obj.new_record? && (klass_or_obj = klass_or_obj.class))
|
236
|
-
path = (proc = kwargs[:index_proc]) ? proc.call(klass_or_obj) : "#{
|
194
|
+
path = (proc = kwargs[:index_proc]) ? proc.call(klass_or_obj) : "#{app_routes.path_for(controller: klass_or_obj.base_class._brick_index, action: :index)}#{filter}"
|
237
195
|
lt_args = [text || "Index for #{klass_or_obj.name.pluralize}", path]
|
238
196
|
else
|
239
197
|
# If there are multiple incoming parameters then last one is probably the actual ID, and first few might be some nested tree of stuff leading up to it
|
240
|
-
path = (proc = kwargs[:show_proc]) ? proc.call(klass_or_obj) : "#{
|
198
|
+
path = (proc = kwargs[:show_proc]) ? proc.call(klass_or_obj) : "#{app_routes.path_for(controller: klass_or_obj.class.base_class._brick_index, action: :show, id: klass_or_obj)}#{filter}"
|
241
199
|
lt_args = [text || "Show this #{klass_or_obj.class.name}", path]
|
242
200
|
end
|
243
201
|
link_to(*lt_args, **kwargs)
|
data/lib/brick/version_number.rb
CHANGED
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,
|
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,
|
646
|
+
send(:resources, res_name.to_sym, **options)
|
647
647
|
end
|
648
648
|
else
|
649
|
-
send(:resources,
|
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
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
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
|
-
|
667
|
-
|
668
|
-
end
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
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
|
-
|
680
|
-
|
681
|
-
|
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
|
1326
|
-
|
1327
|
-
|
1328
|
-
associations
|
1329
|
-
|
1330
|
-
|
1331
|
-
|
1332
|
-
|
1333
|
-
|
1334
|
-
|
1335
|
-
|
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
|
-
|
1338
|
-
|
1339
|
-
|
1340
|
-
|
1341
|
-
|
1342
|
-
|
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
|
-
|
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.
|
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-
|
11
|
+
date: 2022-12-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|