brick 1.0.99 → 1.0.101
Sign up to get free protection for your applications and to get access to all the features.
- 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
|