brick 1.0.127 → 1.0.129

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: 7a424ad95046c33fae8463661b1fb53d770e44e37b503cb68b30fce5725c5ebd
4
- data.tar.gz: 2fc4b004e49497b1b15c864a646717c162e7d7d55edf6913e916fab86ebbcbb7
3
+ metadata.gz: 3b46bf80d393c0d6e4ffea3e8bfc1fbc03dc667902077efc9a887c8ab046a817
4
+ data.tar.gz: 927828e46dfd9ae6b7c14aced0f814bbc1d876e5af14aa872a13d2c13af85083
5
5
  SHA512:
6
- metadata.gz: 5ebf6939ba66e746baf8c84b347630ec4e68951b23dc1efcd72bff47b3b6550c3c8d3444194489aa227a3be153b387552951fdd0fec03dc66a73306df6d6f0d4
7
- data.tar.gz: e3a90e24d98d3bcb47d09e628df9958b101f8dfb9998c97307b791664e8a8b429d12febe73a1e3e322ef3aab054a9e0a103614f2053f58f1b0d2d3e580c9c083
6
+ metadata.gz: 49073fb48479c8df6805a35632ef321efa3144556feb1e2da701044ce110aa6cfcb8ced12186408929b8c3d6280ca6e393e886ba54eea87f0a622a58f9216e8e
7
+ data.tar.gz: eaccf857c54a108c764e786b5e8abd0f54ff5abbcadec558138dc947a5d7e3015fc1a5510a311301947cee815d086018e535a15958357abd3463ab59ee375908
@@ -108,16 +108,16 @@ module ActiveRecord
108
108
  dsl
109
109
  end
110
110
 
111
- def self.brick_parse_dsl(build_array = nil, prefix = [], translations = {}, is_polymorphic = false, dsl = nil, emit_dsl = false)
112
- unless build_array.is_a?(::Brick::JoinArray)
113
- build_array = ::Brick::JoinArray.new.tap { |ary| ary.replace([build_array]) } if build_array.is_a?(::Brick::JoinHash)
114
- build_array = ::Brick::JoinArray.new unless build_array.nil? || build_array.is_a?(Array)
111
+ def self.brick_parse_dsl(join_array = nil, prefix = [], translations = {}, is_polymorphic = false, dsl = nil, emit_dsl = false)
112
+ unless join_array.is_a?(::Brick::JoinArray)
113
+ join_array = ::Brick::JoinArray.new.tap { |ary| ary.replace([join_array]) } if join_array.is_a?(::Brick::JoinHash)
114
+ join_array = ::Brick::JoinArray.new unless join_array.nil? || join_array.is_a?(Array)
115
115
  end
116
116
  prefix = [prefix] unless prefix.is_a?(Array)
117
117
  members = []
118
118
  unless dsl || (dsl = ::Brick.config.model_descrips[name] || brick_get_dsl)
119
119
  # With no DSL available, still put this prefix into the JoinArray so we can get primary key (ID) info from this table
120
- x = prefix.each_with_object(build_array) { |v, s| s[v.to_sym] }
120
+ x = prefix.each_with_object(join_array) { |v, s| s[v.to_sym] }
121
121
  x[prefix.last] = nil unless prefix.empty? # Using []= will "hydrate" any missing part(s) in our whole series
122
122
  return members
123
123
  end
@@ -141,7 +141,7 @@ module ActiveRecord
141
141
  if first_parts
142
142
  if (parts = prefix + first_parts + [parts[-1]]).length > 1 && klass
143
143
  unless is_polymorphic
144
- s = build_array
144
+ s = join_array
145
145
  parts[0..-3].each { |v| s = s[v.to_sym] }
146
146
  s[parts[-2]] = nil # unless parts[-2].empty? # Using []= will "hydrate" any missing part(s) in our whole series
147
147
  end
@@ -153,7 +153,7 @@ module ActiveRecord
153
153
  prefix << parts.shift until parts.empty?
154
154
  end
155
155
  # Expand this entry which refers to an association name
156
- members2, dsl2a = klass.brick_parse_dsl(build_array, prefix + [possible_dsl], translations, is_polymorphic, nil, true)
156
+ members2, dsl2a = klass.brick_parse_dsl(join_array, prefix + [possible_dsl], translations, is_polymorphic, nil, true)
157
157
  members += members2
158
158
  dsl2 << dsl2a
159
159
  dsl3 << dsl2a
@@ -434,7 +434,9 @@ module ActiveRecord
434
434
  @brick_links ||= { '' => table_name }
435
435
  end
436
436
 
437
- def brick_select(params, selects = [], order_by = nil, translations = {}, join_array = ::Brick::JoinArray.new)
437
+ def brick_select(params, selects = [], order_by = nil, translations = {},
438
+ join_array = ::Brick::JoinArray.new,
439
+ cust_col_override = nil)
438
440
  is_add_bts = is_add_hms = true
439
441
 
440
442
  # Build out cust_cols, bt_descrip and hm_counts now so that they are available on the
@@ -467,7 +469,7 @@ module ActiveRecord
467
469
  is_distinct = true
468
470
  distinct!
469
471
  end
470
- wheres[k] = v.split(',')
472
+ wheres[k] = v.is_a?(String) ? v.split(',') : v
471
473
  end
472
474
 
473
475
  # %%% Skip the metadata columns
@@ -506,84 +508,90 @@ module ActiveRecord
506
508
  end
507
509
  end
508
510
 
509
- if join_array.present?
510
- left_outer_joins!(join_array)
511
- # Touching AREL AST walks the JoinDependency tree, and in that process uses our
512
- # "brick_links" patch to find how every AR chain of association names relates to exact
513
- # table correlation names chosen by AREL. We use a duplicate relation object for this
514
- # because an important side-effect of referencing the AST is that the @arel instance
515
- # variable gets set, and this is a signal to ActiveRecord that a relation has now
516
- # become immutable. (We aren't quite ready for our "real deal" relation object to be
517
- # set in stone ... still need to add .select(), and possibly .where() and .order()
518
- # things ... also if there are any HM counts then an OUTER JOIN for each of them out
519
- # to a derived table to do that counting. All of these things need to know proper
520
- # table correlation names, which will now become available in brick_links on the
521
- # rel_dupe object.)
522
- (rel_dupe = dup).arel.ast
523
-
524
- core_selects = selects.dup
525
- id_for_tables = Hash.new { |h, k| h[k] = [] }
526
- field_tbl_names = Hash.new { |h, k| h[k] = {} }
527
- used_col_aliases = {} # Used to make sure there is not a name clash
528
-
529
- # CUSTOM COLUMNS
530
- # ==============
531
- klass._br_cust_cols.each do |k, cc|
532
- if rel_dupe.respond_to?(k) # Name already taken?
533
- # %%% Use ensure_unique here in this kind of fashion:
534
- # cnstr_name = ensure_unique(+"(brick) #{for_tbl}_#{pri_tbl}", bts, hms)
535
- # binding.pry
536
- next
537
- end
511
+ left_outer_joins!(join_array) if join_array.present?
512
+
513
+ # If it's a CollectionProxy (which inherits from Relation) then need to dig out the
514
+ # core Relation object which is found in the association scope.
515
+ rel_dupe = (is_a?(ActiveRecord::Associations::CollectionProxy) ? scope : self).dup
516
+
517
+ # Touching AREL AST walks the JoinDependency tree, and in that process uses our
518
+ # "brick_links" patch to find how every AR chain of association names relates to exact
519
+ # table correlation names chosen by AREL. We use a duplicate relation object for this
520
+ # because an important side-effect of referencing the AST is that the @arel instance
521
+ # variable gets set, and this is a signal to ActiveRecord that a relation has now
522
+ # become immutable. (We aren't quite ready for our "real deal" relation object to be
523
+ # set in stone ... still need to add .select(), and possibly .where() and .order()
524
+ # things ... also if there are any HM counts then an OUTER JOIN for each of them out
525
+ # to a derived table to do that counting. All of these things need to know proper
526
+ # table correlation names, which will now become available in brick_links on the
527
+ # rel_dupe object.)
528
+ rel_dupe.arel.ast
529
+
530
+ core_selects = selects.dup
531
+ id_for_tables = Hash.new { |h, k| h[k] = [] }
532
+ field_tbl_names = Hash.new { |h, k| h[k] = {} }
533
+ used_col_aliases = {} # Used to make sure there is not a name clash
534
+
535
+ # CUSTOM COLUMNS
536
+ # ==============
537
+ (cust_col_override || klass._br_cust_cols).each do |k, cc|
538
+ if rel_dupe.respond_to?(k) # Name already taken?
539
+ # %%% Use ensure_unique here in this kind of fashion:
540
+ # cnstr_name = ensure_unique(+"(brick) #{for_tbl}_#{pri_tbl}", bts, hms)
541
+ # binding.pry
542
+ next
543
+ end
538
544
 
539
- key_klass = nil
540
- key_tbl_name = nil
541
- dest_pk = nil
542
- key_alias = nil
543
- cc.first.each do |cc_part|
544
- dest_klass = cc_part[0..-2].inject(klass) do |kl, cc_part_term|
545
- # %%% Clear column info properly so we can do multiple subsequent requests
546
- # binding.pry unless kl.reflect_on_association(cc_part_term)
547
- kl.reflect_on_association(cc_part_term)&.klass || klass
548
- end
549
- tbl_name = rel_dupe.brick_links[cc_part[0..-2].map(&:to_s).join('.')]
550
- # Deal with the conflict if there are two parts in the custom column named the same,
551
- # "category.name" and "product.name" for instance will end up with aliases of "name"
552
- # and "product__name".
553
- if (cc_part_idx = cc_part.length - 1).zero?
554
- col_alias = "br_cc_#{k}__#{table_name.tr('.', '_')}"
555
- else
556
- while cc_part_idx > 0 &&
557
- (col_alias = "br_cc_#{k}__#{cc_part[cc_part_idx..-1].map(&:to_s).join('__').tr('.', '_')}") &&
558
- used_col_aliases.key?(col_alias)
559
- cc_part_idx -= 1
560
- end
561
- end
562
- used_col_aliases[col_alias] = nil
563
- # Set up custom column links by preparing key_klass and key_alias
564
- # (If there are multiple different tables referenced in the DSL, we end up creating a link to the last one)
565
- if cc[2] && (dest_pk = dest_klass.primary_key)
566
- key_klass = dest_klass
567
- key_tbl_name = tbl_name
568
- cc_part_idx = cc_part.length - 1
569
- while cc_part_idx > 0 &&
570
- (key_alias = "br_cc_#{k}__#{(cc_part[cc_part_idx..-2] + [dest_pk]).map(&:to_s).join('__')}") &&
571
- key_alias != col_alias && # We break out if this key alias does exactly match the col_alias
572
- used_col_aliases.key?(key_alias)
573
- cc_part_idx -= 1
574
- end
545
+ key_klass = nil
546
+ key_tbl_name = nil
547
+ dest_pk = nil
548
+ key_alias = nil
549
+ cc.first.each do |cc_part|
550
+ dest_klass = cc_part[0..-2].inject(klass) do |kl, cc_part_term|
551
+ # %%% Clear column info properly so we can do multiple subsequent requests
552
+ # binding.pry unless kl.reflect_on_association(cc_part_term)
553
+ kl.reflect_on_association(cc_part_term)&.klass || klass
554
+ end
555
+ tbl_name = rel_dupe.brick_links[cc_part[0..-2].map(&:to_s).join('.')]
556
+ # Deal with the conflict if there are two parts in the custom column named the same,
557
+ # "category.name" and "product.name" for instance will end up with aliases of "name"
558
+ # and "product__name".
559
+ if (cc_part_idx = cc_part.length - 1).zero?
560
+ col_alias = "br_cc_#{k}__#{table_name.tr('.', '_')}_#{cc_part.first}"
561
+ else
562
+ while cc_part_idx > 0 &&
563
+ (col_alias = "br_cc_#{k}__#{cc_part[cc_part_idx..-1].map(&:to_s).join('__').tr('.', '_')}") &&
564
+ used_col_aliases.key?(col_alias)
565
+ cc_part_idx -= 1
575
566
  end
576
- selects << "#{tbl_name}.#{cc_part.last} AS #{col_alias}"
577
- cc_part << col_alias
578
567
  end
579
- # Add a key column unless we've already got it
580
- if key_alias && !used_col_aliases.key?(key_alias)
581
- selects << "#{key_tbl_name}.#{dest_pk} AS #{key_alias}"
582
- used_col_aliases[key_alias] = nil
568
+ used_col_aliases[col_alias] = nil
569
+ # Set up custom column links by preparing key_klass and key_alias
570
+ # (If there are multiple different tables referenced in the DSL, we end up creating a link to the last one)
571
+ if cc[2] && (dest_pk = dest_klass.primary_key)
572
+ key_klass = dest_klass
573
+ key_tbl_name = tbl_name
574
+ cc_part_idx = cc_part.length - 1
575
+ while cc_part_idx > 0 &&
576
+ (key_alias = "br_cc_#{k}__#{(cc_part[cc_part_idx..-2] + [dest_pk]).map(&:to_s).join('__')}") &&
577
+ key_alias != col_alias && # We break out if this key alias does exactly match the col_alias
578
+ used_col_aliases.key?(key_alias)
579
+ cc_part_idx -= 1
580
+ end
583
581
  end
584
- cc[2] = key_alias ? [key_klass, key_alias] : nil
582
+ selects << "#{tbl_name}.#{cc_part.last} AS #{col_alias}"
583
+ cc_part << col_alias
585
584
  end
585
+ # Add a key column unless we've already got it
586
+ if key_alias && !used_col_aliases.key?(key_alias)
587
+ selects << "#{key_tbl_name}.#{dest_pk} AS #{key_alias}"
588
+ used_col_aliases[key_alias] = nil
589
+ end
590
+ cc[2] = key_alias ? [key_klass, key_alias] : nil
591
+ end
586
592
 
593
+ # LEFT OUTER JOINs
594
+ unless cust_col_override
587
595
  klass._br_bt_descrip.each do |v|
588
596
  v.last.each do |k1, v1| # k1 is class, v1 is array of columns to snag
589
597
  next unless (tbl_name = rel_dupe.brick_links[v.first.to_s]&.split('.')&.last)
@@ -644,6 +652,7 @@ module ActiveRecord
644
652
  _assoc_names[assoc_name] = [table_alias, klass]
645
653
  end
646
654
  end
655
+
647
656
  # Add derived table JOIN for the has_many counts
648
657
  nix = []
649
658
  klass._br_hm_counts.each do |k, hm|
@@ -781,7 +790,7 @@ module ActiveRecord
781
790
  JOIN (SELECT #{hm_selects.map { |s| "#{'br_t0.' if from_clause}#{s}" }.join(', ')}, COUNT(#{'DISTINCT ' if hm.options[:through]}#{count_column
782
791
  }) AS c_t_ FROM #{from_clause || hm_table_name} GROUP BY #{group_bys.join(', ')}) #{tbl_alias}"
783
792
  self.joins_values |= ["#{join_clause} ON #{on_clause.join(' AND ')}"] # Same as: joins!(...)
784
- end
793
+ end unless cust_col_override
785
794
  while (n = nix.pop)
786
795
  klass._br_hm_counts.delete(n)
787
796
  end
@@ -851,6 +860,22 @@ JOIN (SELECT #{hm_selects.map { |s| "#{'br_t0.' if from_clause}#{s}" }.join(', '
851
860
  wheres unless wheres.empty? # Return the specific parameters that we did use
852
861
  end
853
862
 
863
+ # Build out an AR relation that queries for a list of objects, and include all the appropriate JOINs to later apply DSL using #brick_descrip
864
+ def brick_list
865
+ pks = klass.primary_key.is_a?(String) ? [klass.primary_key] : klass.primary_key
866
+ selects = pks.each_with_object([]) { |pk, s| s << pk unless s.include?(pk) }
867
+ # ActiveStorage compatibility
868
+ selects << 'service_name' if klass.name == 'ActiveStorage::Blob' && ActiveStorage::Blob.columns_hash.key?('service_name')
869
+ selects << 'blob_id' if klass.name == 'ActiveStorage::Attachment' && ActiveStorage::Attachment.columns_hash.key?('blob_id')
870
+ pieces, my_dsl = klass.brick_parse_dsl(join_array = ::Brick::JoinArray.new, [], translations = {}, false, nil, true)
871
+ brick_select(
872
+ where_values_hash, selects, nil, translations, join_array,
873
+ { '_br' => (descrip_cols = [pieces, my_dsl]) }
874
+ )
875
+ order_values = klass.primary_key
876
+ [self.select(selects), descrip_cols]
877
+ end
878
+
854
879
  private
855
880
 
856
881
  def shift_or_first(ary)
@@ -1254,6 +1279,11 @@ class Object
1254
1279
  end
1255
1280
  self.abstract_class = true
1256
1281
  code << " self.abstract_class = true\n"
1282
+ elsif Object.const_defined?('BCrypt') && relation[:cols].include?('password_digest') &&
1283
+ !instance_methods.include?(:password) && respond_to?(:has_secure_password)
1284
+ puts "Appears that the #{full_name} model is intended to hold user account information. Applying #has_secure_password."
1285
+ has_secure_password
1286
+ code << " has_secure_password\n"
1257
1287
  end
1258
1288
  # Accommodate singular or camel-cased table names such as "order_detail" or "OrderDetails"
1259
1289
  code << " self.table_name = '#{self.table_name = matching}'\n" if inheritable_name || table_name != matching
@@ -2718,12 +2748,17 @@ module Brick
2718
2748
  end
2719
2749
  end
2720
2750
  ::Brick.relations.map do |k, v|
2751
+ # next if Brick.config.exclude_tables.include?(k)
2752
+
2721
2753
  tbl_parts = k.split('.')
2722
2754
  tbl_parts.shift if ::Brick.apartment_multitenant && tbl_parts.length > 1 && tbl_parts.first == ::Brick.apartment_default_tenant
2723
2755
  res = tbl_parts.join('.')
2724
- [k, (model = models[res])&.last&.table_name || v[:class_name].constantize.table_name,
2725
- migrations&.fetch(res, nil),
2726
- model&.first]
2756
+ table_name = (model = models[res])&.last&.table_name
2757
+ table_name ||= begin
2758
+ v[:class_name].constantize.table_name
2759
+ rescue
2760
+ end
2761
+ [k, table_name || k, migrations&.fetch(res, nil), model&.first]
2727
2762
  end
2728
2763
  end
2729
2764
 
@@ -58,7 +58,7 @@ module Brick
58
58
  '(Add RGeo gem to parse geometry detail)'
59
59
  end
60
60
  when :binary
61
- ::Brick::Rails.display_binary(val) if val
61
+ ::Brick::Rails.display_binary(val)
62
62
  else
63
63
  if col_type
64
64
  ::Brick::Rails::FormBuilder.hide_bcrypt(val, col_type == :xml)
@@ -69,8 +69,12 @@ module Brick
69
69
  end
70
70
 
71
71
  def display_binary(val)
72
+ return unless val
73
+
72
74
  @image_signatures ||= { (+"\xFF\xD8\xFF\xEE").force_encoding('ASCII-8BIT') => 'jpeg',
73
75
  (+"\xFF\xD8\xFF\xE0\x00\x10\x4A\x46\x49\x46\x00\x01").force_encoding('ASCII-8BIT') => 'jpeg',
76
+ (+"\xFF\xD8\xFF\xDB").force_encoding('ASCII-8BIT') => 'jpeg',
77
+ (+"\xFF\xD8\xFF\xE1").force_encoding('ASCII-8BIT') => 'jpeg',
74
78
  (+"\x89PNG\r\n\x1A\n").force_encoding('ASCII-8BIT') => 'png',
75
79
  '<svg' => 'svg+xml', # %%% Not yet very good detection for SVG
76
80
  (+'BM').force_encoding('ASCII-8BIT') => 'bmp',
@@ -90,7 +94,8 @@ module Brick
90
94
  val = val[object_start...object_start + real_object_size]
91
95
  end
92
96
 
93
- if (signature = @image_signatures.find { |k, _v| val[0...k.length] == k })
97
+ if (signature = @image_signatures.find { |k, _v| val[0...k.length] == k }) ||
98
+ (val[0..3] == 'RIFF' && val[8..11] == 'WEBP' && (signature = 'webp'))
94
99
  if val.length < 500_000
95
100
  "<img src=\"data:image/#{signature.last};base64,#{Base64.encode64(val)}\">"
96
101
  else
@@ -1290,7 +1295,7 @@ erDiagram
1290
1295
  </head>
1291
1296
  <body>
1292
1297
  <div id=\"titleBox\"><div id=\"titleSticky\">
1293
- <p style=\"color: green\"><%= notice %></p>#{"
1298
+ <p style=\"color: green\"><%= notice if request.respond_to?(:flash) %></p>#{"
1294
1299
  #{schema_options}" if schema_options}
1295
1300
  <select id=\"tbl\">#{table_options}</select>
1296
1301
  <table id=\"resourceName\"><tr>
@@ -1411,7 +1416,8 @@ end
1411
1416
  brick_grid(@#{table_name}, @_brick_bt_descrip, @_brick_sequence, @_brick_incl, @_brick_excl,
1412
1417
  cols, poly_cols, bts, #{hms_keys.inspect}, {#{hms_columns.join(', ')}}) %>
1413
1418
 
1414
- #{"<hr><%= link_to \"New #{obj_name}\", new_#{path_obj_name}_path %>" unless @_brick_model.is_view?}
1419
+ #{"<hr><%= link_to(\"New #{new_path_name = "new_#{path_obj_name}_path"
1420
+ obj_name}\", #{new_path_name}) if respond_to?(:#{new_path_name}) %>" unless @_brick_model.is_view?}
1415
1421
  #{script}
1416
1422
  </body>
1417
1423
  </html>
@@ -1423,7 +1429,7 @@ end
1423
1429
  # Must load all models, and then find what table names are represented
1424
1430
  # Easily could be multiple files involved (STI for instance)
1425
1431
  +"#{css}
1426
- <p style=\"color: green\"><%= notice %></p>#{"
1432
+ <p style=\"color: green\"><%= notice if request.respond_to?(:flash) %></p>#{"
1427
1433
  #{schema_options}" if schema_options}
1428
1434
  <select id=\"tbl\">#{table_options}</select>
1429
1435
  <h1>Status</h1>
@@ -1473,7 +1479,7 @@ end
1473
1479
  when 'orphans'
1474
1480
  if is_orphans
1475
1481
  +"#{css}
1476
- <p style=\"color: green\"><%= notice %></p>#{"
1482
+ <p style=\"color: green\"><%= notice if request.respond_to?(:flash) %></p>#{"
1477
1483
  #{schema_options}" if schema_options}
1478
1484
  <select id=\"tbl\">#{table_options}</select>
1479
1485
  <h1>Orphans<%= \" for #\{}\" if false %></h1>
@@ -1520,7 +1526,7 @@ end
1520
1526
  c23.141-70.188,89.141-120.906,167.063-120.906c97.25,0,176,78.813,176,176C511.828,227.078,404.391,119.641,271.844,119.641z\" />
1521
1527
  </svg>
1522
1528
 
1523
- <p style=\"color: green\"><%= notice %></p>#{"
1529
+ <p style=\"color: green\"><%= notice if request.respond_to?(:flash) %></p>#{"
1524
1530
  #{schema_options}" if schema_options}
1525
1531
  <select id=\"tbl\">#{table_options}</select>
1526
1532
  <table><td><h1><%= page_title %></h1></td>
@@ -1555,14 +1561,13 @@ end
1555
1561
  %><%= link_to \"(See all #\{model_name.pluralize})\", see_all_path %>
1556
1562
  #{erd_markup}
1557
1563
  <% if obj
1558
- # path_options = [obj.#{pk}]
1559
- # path_options << { '_brick_schema': } if
1560
- # url = send(:#\{model._brick_index(:singular)}_path, obj.#{pk})
1561
- options = {}
1562
- if ::Brick.config.path_prefix
1563
- path_helper = obj.new_record? ? #{model_name}._brick_index : #{model_name}._brick_index(:singular)
1564
- options[:url] = send(\"#\{path_helper}_path\".to_sym, obj)
1565
- end
1564
+ # path_options = [obj.#{pk}]
1565
+ # path_options << { '_brick_schema': } if
1566
+ options = {}
1567
+ if ::Brick.config.path_prefix
1568
+ path_helper = obj.new_record? ? #{model_name}._brick_index : #{model_name}._brick_index(:singular)
1569
+ options[:url] = send(\"#\{path_helper}_path\".to_sym, obj)
1570
+ end
1566
1571
  %>
1567
1572
  <br><br>
1568
1573
  <%= form_for(obj.becomes(#{model_name}), options) do |f| %>
@@ -1570,11 +1575,11 @@ end
1570
1575
  <% has_fields = false
1571
1576
  @#{obj_name}.attributes.each do |k, val|
1572
1577
  next if !(col = #{model_name}.columns_hash[k]) ||
1573
- (#{(pk || []).inspect}.include?(k) && !bts.key?(k)) ||
1578
+ (#{(pk.map(&:to_s) || []).inspect}.include?(k) && !bts.key?(k)) ||
1574
1579
  ::Brick.config.metadata_columns.include?(k) %>
1575
1580
  <tr>
1576
1581
  <th class=\"show-field\"<%= \" title=\\\"#\{col.comment}\\\"\".html_safe if col.respond_to?(:comment) && !col.comment.blank? %>>
1577
- <% has_fields = true
1582
+ <% has_fields = true
1578
1583
  if (bt = bts[k])
1579
1584
  # Add a final member in this array with descriptive options to be used in <select> drop-downs
1580
1585
  bt_name = bt[1].map { |x| x.first.name }.join('/')
@@ -1602,7 +1607,15 @@ end
1602
1607
  if bt.length < 4
1603
1608
  bt << (option_detail = [[\"(No #\{bt_name\} chosen)\", '^^^brick_NULL^^^']])
1604
1609
  # %%% Accommodate composite keys for obj.pk at the end here
1605
- bt_class&.order(obj_pk = bt_class.primary_key)&.each { |obj| option_detail << [obj.brick_descrip(nil, obj_pk), obj.send(obj_pk)] }
1610
+ collection, descrip_cols = bt_class&.order(obj_pk = bt_class.primary_key).brick_list
1611
+ collection&.each do |obj|
1612
+ option_detail << [
1613
+ obj.brick_descrip(
1614
+ descrip_cols&.first&.map { |col| obj.send(col.last) },
1615
+ obj_pk
1616
+ ), obj.send(obj_pk)
1617
+ ]
1618
+ end
1606
1619
  end %>
1607
1620
  BT <%= bt_class&.bt_link(bt.first) || orig_poly_name %>
1608
1621
  <% else %>
@@ -1619,7 +1632,11 @@ end
1619
1632
  <% else %>
1620
1633
  <tr><td colspan=\"2\">(No displayable fields)</td></tr>
1621
1634
  <% end %>
1622
- </table>
1635
+ </table>#{
1636
+ "<%= binary = begin
1637
+ ::Brick::Rails.display_binary(obj&.blob&.download)&.html_safe
1638
+ rescue
1639
+ end %>" if model_name == 'ActiveStorage::Attachment'}
1623
1640
  <% end %>
1624
1641
 
1625
1642
  #{unless args.first == 'new'
@@ -1634,34 +1651,51 @@ end
1634
1651
  obj_pk = (pk.is_a?(Array) ? pk : [pk]).each_with_object([]) { |pk_part, s| s << "#{hm_singular_name}.#{pk_part}" }.join(', ')
1635
1652
  poly_fix = if (poly_type = (hm.first.options[:as] && hm.first.type))
1636
1653
  "
1637
- # Let's fix an unexpected \"feature\" of AR -- when going through a polymorphic has_many
1638
- # association that points to an STI model then filtering for the __able_type column is done
1639
- # with a .where(). And the polymorphic class name it points to is the base class name of
1640
- # the STI model instead of its subclass.
1641
- poly_type = #{poly_type.inspect}
1642
- #{ (inh_col = @_brick_model.inheritance_column).present? &&
1643
- " if poly_type && @#{obj_name}.respond_to?(:#{inh_col}) &&
1644
- (base_type = collection.where_values_hash[poly_type])
1645
- collection = collection.rewhere(poly_type => [base_type, @#{obj_name}.#{inh_col}])
1646
- end"}"
1654
+ # Let's fix an unexpected \"feature\" of AR -- when going through a polymorphic has_many
1655
+ # association that points to an STI model then filtering for the __able_type column is done
1656
+ # with a .where(). And the polymorphic class name it points to is the base class name of
1657
+ # the STI model instead of its subclass.
1658
+ poly_type = #{poly_type.inspect}
1659
+ #{ (inh_col = @_brick_model.inheritance_column).present? &&
1660
+ " if poly_type && @#{obj_name}.respond_to?(:#{inh_col}) &&
1661
+ (base_type = collection.where_values_hash[poly_type])
1662
+ collection = collection.rewhere(poly_type => [base_type, @#{obj_name}.#{inh_col}])
1663
+ end"}"
1647
1664
  end
1648
1665
  s << "<table id=\"#{hm_name}\" class=\"shadow\">
1649
1666
  <tr><th>#{hm[1]}#{' poly' if hm[0].options[:as]} #{hm[3]}</th></tr>
1650
- <% collection = @#{obj_name}.#{hm_name}
1651
- collection = case collection
1652
- when ActiveRecord::Associations::CollectionProxy#{
1653
- poly_fix}
1654
- collection.order(#{pk.inspect})
1655
- when ActiveRecord::Base # Object from a has_one
1656
- [collection]
1657
- else # We get an array back when AR < 4.2
1658
- collection.to_a.compact
1659
- end
1660
- if collection.empty? %>
1667
+ <% if (assoc = @#{obj_name}.class.reflect_on_association(:#{hm_name})).macro == :has_one &&
1668
+ assoc.options&.fetch(:through, nil).nil?
1669
+ # In order to apply DSL properly, evaluate this HO the other way around as if it were as a BT
1670
+ collection = assoc.klass.where(assoc.foreign_key => @#{obj_name}.#{pk})
1671
+ collection = collection.instance_exec(&assoc.scopes.first) if assoc.scopes.present?
1672
+ if assoc.klass.name == 'ActiveStorage::Attachment'
1673
+ br_descrip = begin
1674
+ ::Brick::Rails.display_binary(obj.send(assoc.name)&.blob&.download)&.html_safe
1675
+ rescue
1676
+ end
1677
+ end
1678
+ else
1679
+ collection = @#{obj_name}.#{hm_name}
1680
+ end
1681
+ case collection
1682
+ when ActiveRecord::Relation # has_many (which comes in as a CollectionProxy) or a has_one#{
1683
+ poly_fix}
1684
+ collection2, descrip_cols = collection.brick_list
1685
+ when ActiveRecord::Base # Object from a has_one :through
1686
+ collection2 = [collection]
1687
+ else # We get an array back when AR < 4.2
1688
+ collection2 = collection.to_a.compact
1689
+ end
1690
+ collection2 = collection2.uniq
1691
+ if collection2.empty? %>
1661
1692
  <tr><td>(none)</td></tr>
1662
- <% else %>
1663
- <% collection.uniq.each do |#{hm_singular_name}| %>
1664
- <tr><td><%= link_to(#{hm_singular_name}.brick_descrip, #{hm.first.klass._brick_index(:singular)}_path(slashify(#{obj_pk}))) %></td></tr>
1693
+ <% else
1694
+ collection2.each do |#{hm_singular_name}| %>
1695
+ <tr><td><%= br_descrip ||= #{hm_singular_name}.brick_descrip(
1696
+ descrip_cols&.first&.map { |col| #{hm_singular_name}.send(col.last) }
1697
+ )
1698
+ link_to(br_descrip, #{hm.first.klass._brick_index(:singular)}_path(slashify(#{obj_pk}))) %></td></tr>
1665
1699
  <% end %>
1666
1700
  <% end %>
1667
1701
  </table>"
@@ -115,7 +115,14 @@ module Brick::Rails::FormTags
115
115
  if col[2] == 'HO'
116
116
  descrips = bt_descrip[col_name.to_sym][hm_klass]
117
117
  if (ho_id = (ho_id_col = descrips.last).map { |id_col| obj.send(id_col.to_sym) })&.first
118
- ho_txt = hm_klass.brick_descrip(obj, descrips[0..-2].map { |id| obj.send(id.last[0..62]) }, ho_id_col)
118
+ ho_txt = if hm_klass.name == 'ActiveStorage::Attachment'
119
+ begin
120
+ ::Brick::Rails.display_binary(obj.send(col[3])&.blob&.download)&.html_safe
121
+ rescue
122
+ end
123
+ else
124
+ hm_klass.brick_descrip(obj, descrips[0..-2].map { |id| obj.send(id.last[0..62]) }, ho_id_col)
125
+ end
119
126
  out << link_to(ho_txt, send("#{hm_klass.base_class._brick_index(:singular)}_path".to_sym, ho_id))
120
127
  end
121
128
  else
@@ -5,7 +5,7 @@ module Brick
5
5
  module VERSION
6
6
  MAJOR = 1
7
7
  MINOR = 0
8
- TINY = 127
8
+ TINY = 129
9
9
 
10
10
  # PRE is nil unless it's a pre-release (beta, RC, etc.)
11
11
  PRE = nil
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.127
4
+ version: 1.0.129
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lorin Thwaits
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-04-05 00:00:00.000000000 Z
11
+ date: 2023-04-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord