brick 1.0.127 → 1.0.129

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 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