brick 1.0.34 → 1.0.37

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: 9d1e2f8b6ff7ca3fa7fcd129c33de3dfe6e674b6da154b9a64e094c65a3a152a
4
- data.tar.gz: 30e39f62458a46854f56b2a6decbfe5ea42a4bb5325e81ed76f21400aae8e252
3
+ metadata.gz: '0178c8135edf190cf65ae2a4b274bde10cc5410f33adab7337798d98636f810f'
4
+ data.tar.gz: c4c51e9e22548f9f49a08a7550eb003c0075b65bac70fffea82b919b7aa07131
5
5
  SHA512:
6
- metadata.gz: 14c6bae09e34f53126e2003cbc7256c4b32f4a4219d42f1f7e94ca83211debf3704fa6c170cd6231d89e26eb168f282d1dea7eff7150ef1a013364aeb4eb65c3
7
- data.tar.gz: 7f33aa5c89be2e8401f4cda0ea6cecb6e01639934a2df1e7b00bd88d065bf3cc9b748bebb1691d51c1b04114fba3b1739a7820c7614f4eb84d52494bd4cc769e
6
+ metadata.gz: b6ad8492e3b19f526af3cc69f53f30e3a4de0f172f73362d36f6dbac884f7137bb7a3944f99054f61279c2fdc27989e9b840e68cb48c23aa378f6ac4bd4d2cfb
7
+ data.tar.gz: def025f413aa8c89f8f603f4e3422427f9d71b10b7c57c0db6d5fb750b0e26352dc88f3d85f01b526127d54a789e6b056dc7acee64e9046909a039e576421587
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_record/version'
4
+
5
+ # ActiveRecord before 4.0 didn't have #version
6
+ unless ActiveRecord.respond_to?(:version)
7
+ module ActiveRecord
8
+ def self.version
9
+ ::Gem::Version.new(ActiveRecord::VERSION::STRING)
10
+ end
11
+ end
12
+ end
13
+
14
+ # In ActiveSupport older than 5.0, the duplicable? test tries to new up a BigDecimal,
15
+ # and Ruby 2.6 and later deprecates #new. This removes the warning from BigDecimal.
16
+ # This compatibility needs to be put into place in the application's "config/boot.rb"
17
+ # file by having the line "require 'brick/compatibility'" to be the last line in that
18
+ # file.
19
+ require 'bigdecimal'
20
+ if ::Gem::Version.new(RUBY_VERSION) >= ::Gem::Version.new('2.6') &&
21
+ ActiveRecord.version < ::Gem::Version.new('5.0')
22
+ def BigDecimal.new(*args, **kwargs)
23
+ BigDecimal(*args, **kwargs)
24
+ end
25
+ end
@@ -203,7 +203,9 @@ module ActiveRecord
203
203
  model_underscore = name.underscore
204
204
  assoc_name = CGI.escapeHTML(assoc_name.to_s)
205
205
  model_path = Rails.application.routes.url_helpers.send("#{model_underscore.tr('/', '_').pluralize}_path".to_sym)
206
- link = Class.new.extend(ActionView::Helpers::UrlHelper).link_to(name, model_path)
206
+ av_class = Class.new.extend(ActionView::Helpers::UrlHelper)
207
+ av_class.extend(ActionView::Helpers::TagHelper) if ActionView.version < ::Gem::Version.new('6.1')
208
+ link = av_class.link_to(name, model_path)
207
209
  model_underscore == assoc_name ? link : "#{assoc_name}-#{link}".html_safe
208
210
  end
209
211
 
@@ -409,7 +411,6 @@ module ActiveRecord
409
411
  hm_counts.each do |k, hm|
410
412
  associative = nil
411
413
  count_column = if hm.options[:through]
412
- # binding.pry if associatives[hm.name].nil?
413
414
  fk_col = (associative = associatives[hm.name]).foreign_key
414
415
  hm.foreign_key
415
416
  else
@@ -500,8 +501,9 @@ if ActiveSupport::Dependencies.respond_to?(:autoload_module!) # %%% Only works w
500
501
  alias _brick_autoload_module! autoload_module!
501
502
  def autoload_module!(*args)
502
503
  into, const_name, qualified_name, path_suffix = args
503
- base_class_name = ::Brick.config.sti_namespace_prefixes&.fetch("::#{into.name}::", nil)
504
- base_class_name = "::#{base_class_name}" unless base_class_name.start_with?('::')
504
+ if (base_class_name = ::Brick.config.sti_namespace_prefixes&.fetch("::#{into.name}::", nil))
505
+ base_class_name = "::#{base_class_name}" unless base_class_name.start_with?('::')
506
+ end
505
507
  if (base_class = base_class_name&.constantize)
506
508
  ::Brick.sti_models[qualified_name] = { base: base_class }
507
509
  # Build subclass and place it into the specially STI-namespaced module
@@ -777,9 +779,12 @@ class Object
777
779
  options = { through: through.to_sym }
778
780
  if relation[:fks].any? { |k, v| v[:assoc_name] == hmt_name }
779
781
  hmt_name = "#{hmt_name.singularize}_#{fk.first[:assoc_name]}"
780
- # binding.pry if relation[:fks].any? { |k, v| v[:assoc_name] == hmt_name }
781
- options[:class_name] = fk.first[:inverse_table].singularize.camelize
782
- options[:foreign_key] = fk.first[:fk].to_sym
782
+ # Was:
783
+ # options[:class_name] = fk.first[:inverse_table].singularize.camelize
784
+ # options[:foreign_key] = fk.first[:fk].to_sym
785
+ far_assoc = relations[fk.first[:inverse_table]][:fks].find { |_k, v| v[:assoc_name] == fk.last }
786
+ options[:class_name] = far_assoc.last[:inverse_table].singularize.camelize
787
+ options[:foreign_key] = far_assoc.last[:fk].to_sym
783
788
  end
784
789
  options[:source] = fk.last.to_sym unless hmt_name.singularize == fk.last
785
790
  code << " has_many :#{hmt_name}#{options.map { |opt| ", #{opt.first}: #{opt.last.inspect}" }.join}\n"
@@ -942,7 +947,6 @@ class Object
942
947
  }
943
948
  s
944
949
  end
945
- # binding.pry
946
950
  render inline: json.to_json, content_type: request.format
947
951
  return
948
952
  end
@@ -959,7 +963,8 @@ class Object
959
963
  return
960
964
  end
961
965
 
962
- order = pk.each_with_object([]) { |pk_part, s| s << "#{model.table_name}.#{pk_part}" }
966
+ quoted_table_name = model.table_name.split('.').map { |x| "\"#{x}\"" }.join('.')
967
+ order = pk.each_with_object([]) { |pk_part, s| s << "#{quoted_table_name}.\"#{pk_part}\"" }
963
968
  ar_relation = order.present? ? model.order("#{order.join(', ')}") : model.all
964
969
  @_brick_params = ar_relation.brick_select(params, (selects = []), (bt_descrip = {}), (hm_counts = {}), (join_array = ::Brick::JoinArray.new))
965
970
  # %%% Add custom HM count columns
@@ -974,7 +979,8 @@ class Object
974
979
  @_brick_join_array = join_array
975
980
  end
976
981
 
977
- if model&.primary_key
982
+ is_pk_string = nil
983
+ if (pk_col = model&.primary_key)
978
984
  code << " def show\n"
979
985
  code << (find_by_id = " id = params[:id]&.split(/[\\/,_]/)
980
986
  id = id.first if id.is_a?(Array) && id.length == 1
@@ -982,7 +988,12 @@ class Object
982
988
  code << " end\n"
983
989
  self.define_method :show do
984
990
  ::Brick.set_db_schema(params)
985
- id = params[:id]&.split(/[\/,_]/)
991
+ id = if model.columns_hash[pk_col]&.type == :string
992
+ is_pk_string = true
993
+ params[:id]
994
+ else
995
+ params[:id]&.split(/[\/,_]/)
996
+ end
986
997
  id = id.first if id.is_a?(Array) && id.length == 1
987
998
  instance_variable_set("@#{singular_table_name}".to_sym, model.find(id))
988
999
  end
@@ -1021,7 +1032,7 @@ class Object
1021
1032
  # return
1022
1033
  end
1023
1034
 
1024
- id = params[:id]&.split(/[\/,_]/)
1035
+ id = is_pk_string ? params[:id] : params[:id]&.split(/[\/,_]/)
1025
1036
  id = id.first if id.is_a?(Array) && id.length == 1
1026
1037
  instance_variable_set("@#{singular_table_name}".to_sym, (obj = model.find(id)))
1027
1038
  obj = obj.first if obj.is_a?(Array)
@@ -1047,19 +1058,15 @@ class Object
1047
1058
  end
1048
1059
 
1049
1060
  def _brick_get_hm_assoc_name(relation, hm_assoc)
1050
- if relation[:hm_counts][hm_assoc[:assoc_name]]&.> 1
1051
- # binding.pry if (same_name = relation[:fks].find { |x| x.last[:assoc_name] == hm_assoc[:assoc_name] && x.last != hm_assoc }) #&&
1052
- # x.last[:alternate_name] == hm_assoc[:alternate_name] })
1053
- # relation[:fks].any? { |k, v| v[:assoc_name] == new_alt_name }
1061
+ if (relation[:hm_counts][hm_assoc[:assoc_name]]&.> 1) &&
1062
+ hm_assoc[:alternate_name] != hm_assoc[:inverse][:assoc_name]
1054
1063
  plural = ActiveSupport::Inflector.pluralize(hm_assoc[:alternate_name])
1055
- # binding.pry if hm_assoc[:assoc_name] == 'issue_issue_duplicates'
1056
1064
  new_alt_name = (hm_assoc[:alternate_name] == name.underscore) ? "#{hm_assoc[:assoc_name].singularize}_#{plural}" : plural
1057
1065
  # uniq = 1
1058
1066
  # while same_name = relation[:fks].find { |x| x.last[:assoc_name] == hm_assoc[:assoc_name] && x.last != hm_assoc }
1059
1067
  # hm_assoc[:assoc_name] = "#{hm_assoc_name}_#{uniq += 1}"
1060
1068
  # end
1061
1069
  # puts new_alt_name
1062
- # binding.pry if new_alt_name == 'issue_duplicates'
1063
1070
  # hm_assoc[:assoc_name] = new_alt_name
1064
1071
  [new_alt_name, true]
1065
1072
  else
@@ -1101,9 +1108,11 @@ module ActiveRecord::ConnectionHandling
1101
1108
  # Only for Postgres? (Doesn't work in sqlite3)
1102
1109
  # puts ActiveRecord::Base.execute_sql("SELECT current_setting('SEARCH_PATH')").to_a.inspect
1103
1110
 
1111
+ is_postgres = nil
1104
1112
  schema_sql = 'SELECT NULL AS table_schema;'
1105
1113
  case ActiveRecord::Base.connection.adapter_name
1106
1114
  when 'PostgreSQL'
1115
+ is_postgres = true
1107
1116
  if (is_multitenant = (multitenancy = ::Brick.config.schema_behavior[:multitenant]) &&
1108
1117
  (sta = multitenancy[:schema_to_analyse]) != 'public')
1109
1118
  ::Brick.default_schema = schema = sta
@@ -1151,7 +1160,8 @@ module ActiveRecord::ConnectionHandling
1151
1160
  # %%% Retrieve internal ActiveRecord table names like this:
1152
1161
  # ActiveRecord::Base.internal_metadata_table_name, ActiveRecord::Base.schema_migrations_table_name
1153
1162
  # For if it's not SQLite -- so this is the Postgres and MySQL version
1154
- sql ||= "SELECT t.table_schema AS schema, t.table_name AS relation_name, t.table_type,
1163
+ sql ||= "SELECT t.table_schema AS schema, t.table_name AS relation_name, t.table_type,#{"
1164
+ pg_catalog.obj_description((t.table_schema || '.' || t.table_name)::regclass, 'pg_class') AS table_description," if is_postgres}
1155
1165
  c.column_name, c.data_type,
1156
1166
  COALESCE(c.character_maximum_length, c.numeric_precision) AS max_length,
1157
1167
  tc.constraint_type AS const, kcu.constraint_name AS \"key\",
@@ -1178,7 +1188,8 @@ module ActiveRecord::ConnectionHandling
1178
1188
  case ActiveRecord::Base.connection.adapter_name
1179
1189
  when 'PostgreSQL', 'SQLite' # These bring back a hash for each row because the query uses column aliases
1180
1190
  # schema ||= 'public' if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
1181
- ActiveRecord::Base.execute_sql(sql, ActiveRecord::Base.internal_metadata_table_name, ActiveRecord::Base.schema_migrations_table_name).each do |r|
1191
+ ar_imtn = ActiveRecord.version >= ::Gem::Version.new('5.0') ? ActiveRecord::Base.internal_metadata_table_name : ''
1192
+ ActiveRecord::Base.execute_sql(sql, ActiveRecord::Base.schema_migrations_table_name, ar_imtn).each do |r|
1182
1193
  # If Apartment gem lists the table as being associated with a non-tenanted model then use whatever it thinks
1183
1194
  # is the default schema, usually 'public'.
1184
1195
  schema_name = if ::Brick.config.schema_behavior[:multitenant]
@@ -1189,6 +1200,7 @@ module ActiveRecord::ConnectionHandling
1189
1200
  relation_name = schema_name ? "#{schema_name}.#{r['relation_name']}" : r['relation_name']
1190
1201
  relation = relations[relation_name]
1191
1202
  relation[:isView] = true if r['table_type'] == 'VIEW'
1203
+ relation[:description] = r['table_description'] if r['table_description']
1192
1204
  col_name = r['column_name']
1193
1205
  key = case r['const']
1194
1206
  when 'PRIMARY KEY'
@@ -1364,7 +1376,7 @@ module Brick
1364
1376
  is_schema = if ::Brick.config.schema_behavior[:multitenant]
1365
1377
  # If Apartment gem lists the primary table as being associated with a non-tenanted model
1366
1378
  # then use 'public' schema for the primary table
1367
- if apartment&.excluded_models.include?(fk[4].singularize.camelize)
1379
+ if apartment && apartment&.excluded_models.include?(fk[4].singularize.camelize)
1368
1380
  fk[3] = Apartment.default_schema
1369
1381
  true
1370
1382
  end
@@ -1446,7 +1458,6 @@ module Brick
1446
1458
  else
1447
1459
  fk[1]
1448
1460
  end
1449
- # binding.pry if inv_tbl == 'issue_issue_duplicates' # inverse_table goofed?
1450
1461
  assoc_hm = hms[hm_cnstr_name] = { is_bt: false, fk: fk[2], assoc_name: for_tbl.pluralize, alternate_name: bt_assoc_name,
1451
1462
  inverse_table: inv_tbl, inverse: assoc_bt }
1452
1463
  assoc_hm[:polymorphic] = true if is_polymorphic
@@ -141,9 +141,14 @@ module Brick
141
141
  display: none;
142
142
  }
143
143
 
144
+ #headerTop {
145
+ position: sticky;
146
+ top: 0px;
147
+ background-color: white;
148
+ z-index: 1;
149
+ }
144
150
  table {
145
151
  border-collapse: collapse;
146
- margin: 25px 0;
147
152
  font-size: 0.9em;
148
153
  font-family: sans-serif;
149
154
  min-width: 400px;
@@ -216,12 +221,17 @@ input[type=submit] {
216
221
  <% def is_bcrypt?(val)
217
222
  val.is_a?(String) && val.length == 60 && val.start_with?('$2a$')
218
223
  end
219
- def hide_bcrypt(val)
224
+ def hide_bcrypt(val, max_len = 200)
220
225
  if is_bcrypt?(val)
221
226
  '(hidden)'
222
- elsif val.is_a?(String) && val.encoding.name != 'UTF-8'
223
- val[0..1000].force_encoding('UTF-8')
224
227
  else
228
+ if val.is_a?(String)
229
+ if val.length > max_len
230
+ val = val[0...max_len]
231
+ val << '...'
232
+ end
233
+ val.force_encoding('UTF-8') unless val.encoding.name == 'UTF-8'
234
+ end
225
235
  val
226
236
  end
227
237
  end %>"
@@ -250,40 +260,45 @@ end %>"
250
260
  var schemaSelect = document.getElementById(\"schema\");
251
261
  var tblSelect = document.getElementById(\"tbl\");
252
262
  var brickSchema;
253
- if (schemaSelect) {
254
- brickSchema = changeout(location.href, \"_brick_schema\");
255
- if (brickSchema) {
256
- [... document.getElementsByTagName(\"A\")].forEach(function (a) { a.href = changeout(a.href, \"_brick_schema\", brickSchema); });
263
+ var #{table_name}HtColumns;
264
+
265
+ // This PageTransitionEvent fires when the page first loads, as well as after any other history
266
+ // transition such as when using the browser's Back and Forward buttons.
267
+ window.addEventListener(\"pageshow\", function() {
268
+ if (schemaSelect) { // First drop-down is only present if multitenant
269
+ brickSchema = changeout(location.href, \"_brick_schema\");
270
+ if (brickSchema) {
271
+ [... document.getElementsByTagName(\"A\")].forEach(function (a) { a.href = changeout(a.href, \"_brick_schema\", brickSchema); });
272
+ }
273
+ schemaSelect.value = brickSchema || \"public\";
274
+ schemaSelect.focus();
275
+ schemaSelect.addEventListener(\"change\", function () {
276
+ // If there's an ID then remove it (trim after selected table)
277
+ location.href = changeout(location.href, \"_brick_schema\", this.value, tblSelect.value);
278
+ });
257
279
  }
258
- schemaSelect.value = brickSchema || \"public\";
259
- schemaSelect.focus();
260
- schemaSelect.addEventListener(\"change\", function () {
261
- // If there's an ID then remove it (trim after selected table)
262
- location.href = changeout(location.href, \"_brick_schema\", this.value, tblSelect.value);
263
- });
264
- }
265
- [... document.getElementsByTagName(\"FORM\")].forEach(function (form) {
266
- if (brickSchema)
267
- form.action = changeout(form.action, \"_brick_schema\", brickSchema);
268
- form.addEventListener('submit', function (ev) {
269
- [... ev.target.getElementsByTagName(\"SELECT\")].forEach(function (select) {
270
- if (select.value === \"^^^brick_NULL^^^\")
271
- select.value = null;
280
+ [... document.getElementsByTagName(\"FORM\")].forEach(function (form) {
281
+ if (brickSchema)
282
+ form.action = changeout(form.action, \"_brick_schema\", brickSchema);
283
+ form.addEventListener('submit', function (ev) {
284
+ [... ev.target.getElementsByTagName(\"SELECT\")].forEach(function (select) {
285
+ if (select.value === \"^^^brick_NULL^^^\")
286
+ select.value = null;
287
+ });
288
+ return true;
272
289
  });
273
- return true;
274
290
  });
275
- });
276
291
 
277
- if (tblSelect) {
278
- tblSelect.value = changeout(location.href)[0];
279
- if (tblSelect.selectedIndex < 0) tblSelect.value = changeout(location.href)[1];
280
- tblSelect.addEventListener(\"change\", function () {
281
- var lhr = changeout(location.href, null, this.value);
282
- if (brickSchema)
283
- lhr = changeout(lhr, \"_brick_schema\", schemaSelect.value);
284
- location.href = lhr;
285
- });
286
- }
292
+ if (tblSelect) { // Always present
293
+ tblSelect.value = changeout(location.href)[schemaSelect ? 1 : 0];
294
+ tblSelect.addEventListener(\"change\", function () {
295
+ var lhr = changeout(location.href, null, this.value);
296
+ if (brickSchema)
297
+ lhr = changeout(lhr, \"_brick_schema\", schemaSelect.value);
298
+ location.href = lhr;
299
+ });
300
+ }
301
+ });
287
302
 
288
303
  function changeout(href, param, value, trimAfter) {
289
304
  var hrefParts = href.split(\"?\");
@@ -307,6 +322,42 @@ function changeout(href, param, value, trimAfter) {
307
322
  params[param] = value;
308
323
  return hrefParts[0] + \"?\" + Object.keys(params).reduce(function (s, v) { s.push(v + \"=\" + params[v]); return s; }, []).join(\"&\");
309
324
  }
325
+
326
+ // Snag first TR for sticky header
327
+ var grid = document.getElementById(\"#{table_name}\");
328
+ #{table_name}HtColumns = grid && [grid.getElementsByTagName(\"TR\")[0]];
329
+ var headerTop = document.getElementById(\"headerTop\");
330
+ function setHeaderSizes() {
331
+ // console.log(\"start\");
332
+ // See if the headerTop is already populated
333
+ // %%% Grab the TRs from headerTop, clear it out, do this stuff, add them back
334
+ headerTop.innerHTML = \"\"; // %%% Would love to not have to clear it out like this every time! (Currently doing this to support resize events.)
335
+ var isEmpty = headerTop.childElementCount === 0;
336
+ // Set up proper sizings of sticky column header
337
+ var node;
338
+ for (var j = 0; j < #{table_name}HtColumns.length; ++j) {
339
+ var row = #{table_name}HtColumns[j];
340
+ var tr = isEmpty ? document.createElement(\"TR\") : headerTop.childNodes[j];
341
+ tr.innerHTML = row.innerHTML.trim();
342
+ // Match up widths from the original column headers
343
+ for (var i = 0; i < row.childNodes.length; ++i) {
344
+ node = row.childNodes[i];
345
+ if (node.nodeType === 1) {
346
+ var style = tr.childNodes[i].style;
347
+ style.minWidth = style.maxWidth = getComputedStyle(node).width;
348
+ }
349
+ }
350
+ if (isEmpty) headerTop.appendChild(tr);
351
+ }
352
+ grid.style.marginTop = \"-\" + getComputedStyle(headerTop).height;
353
+ // console.log(\"end\");
354
+ }
355
+ if (headerTop) {
356
+ setHeaderSizes();
357
+ window.addEventListener('resize', function(event) {
358
+ setHeaderSizes();
359
+ }, true);
360
+ }
310
361
  </script>"
311
362
  inline = case args.first
312
363
  when 'index'
@@ -366,7 +417,6 @@ function changeout(href, param, value, trimAfter) {
366
417
 
367
418
  async function updateSignInStatus(isSignedIn) {
368
419
  if (isSignedIn) {
369
- console.log(\"turds!\");
370
420
  await gapi.client.sheets.spreadsheets.create({
371
421
  properties: {
372
422
  title: #{table_name.inspect},
@@ -411,14 +461,15 @@ function changeout(href, param, value, trimAfter) {
411
461
  <p style=\"color: green\"><%= notice %></p>#{"
412
462
  <select id=\"schema\">#{schema_options}</select>" if ::Brick.config.schema_behavior[:multitenant] && ::Brick.db_schemas.length > 1}
413
463
  <select id=\"tbl\">#{table_options}</select>
414
- <h1>#{model_plural = model_name.pluralize}</h1>#{template_link}
415
-
416
- <% if @_brick_params&.present? %>
464
+ <h1>#{model_plural = model_name.pluralize}</h1>#{template_link}<%
465
+ if (relation = Brick.relations[#{model_name}.table_name])[:description] %><%=
466
+ relation.fetch(:description, nil) %><br><%
467
+ end
468
+ if @_brick_params&.present? %>
417
469
  <% if @_brick_params.length == 1 # %%% Does not yet work with composite keys
418
470
  k, id = @_brick_params.first
419
471
  id = id.first if id.is_a?(Array) && id.length == 1
420
472
  origin = (key_parts = k.split('.')).length == 1 ? #{model_name} : #{model_name}.reflect_on_association(key_parts.first).klass
421
- # binding.pry
422
473
  if (destination_fk = Brick.relations[origin.table_name][:fks].values.find { |fk| puts fk.inspect; fk[:fk] == key_parts.last }) &&
423
474
  (obj = (destination = origin.reflect_on_association(destination_fk[:assoc_name])&.klass)&.find(id)) %>
424
475
  <h3>for <%= link_to \"#{"#\{obj.brick_descrip\} (#\{destination.name\})\""}, send(\"#\{destination.name.underscore.tr('/', '_')\}_path\".to_sym, id) %></h3><%
@@ -426,36 +477,40 @@ function changeout(href, param, value, trimAfter) {
426
477
  end %>
427
478
  (<%= link_to 'See all #{model_plural.split('::').last}', #{path_obj_name.pluralize}_path %>)
428
479
  <% end %>
480
+ <br>
481
+ <table id=\"headerTop\">
429
482
  <table id=\"#{table_name}\">
430
- <thead><tr>#{'<th></th>' if pk.present?}
431
- <% @#{table_name}.columns.map(&:name).each do |col| %>
432
- <% next if (#{(pk || []).inspect}.include?(col) && #{model_name}.column_for_attribute(col).type == :integer && !bts.key?(col)) ||
433
- ::Brick.config.metadata_columns.include?(col) || poly_cols.include?(col) %>
434
- <th>
435
- <% if (bt = bts[col]) %>
483
+ <thead><tr>#{'<th></th>' if pk.present?}<%
484
+ col_order = []
485
+ @#{table_name}.columns.each do |col|
486
+ col_name = col.name
487
+ next if (#{(pk || []).inspect}.include?(col_name) && col.type == :integer && !bts.key?(col_name)) ||
488
+ ::Brick.config.metadata_columns.include?(col_name) || poly_cols.include?(col_name)
489
+
490
+ col_order << col_name
491
+ %><th<%= \" title = \\\"#\{col.comment}\\\"\".html_safe unless col.comment.blank? %>><%
492
+ if (bt = bts[col_name]) %>
436
493
  BT <%
437
494
  bt[1].each do |bt_pair| %><%=
438
495
  bt_pair.first.bt_link(bt.first) %> <%
439
496
  end %><%
440
497
  else %><%=
441
- col %><%
442
- end %>
443
- </th>
444
- <% end %>
445
- <%# Consider getting the name from the association -- h.first.name -- if a more \"friendly\" alias should be used for a screwy table name %>
446
- #{hms_headers.map { |h| "<th>#{h[1]} <%= link_to('#{h[2]}', #{h.first.klass.name.underscore.tr('/', '_').pluralize}_path) %></th>\n" }.join}
447
- </tr></thead>
498
+ col_name %><%
499
+ end
500
+ %></th><%
501
+ end
502
+ # Consider getting the name from the association -- h.first.name -- if a more \"friendly\" alias should be used for a screwy table name
503
+ %>#{hms_headers.map { |h| "<th>#{h[1]} <%= link_to('#{h[2]}', #{h.first.klass.name.underscore.tr('/', '_').pluralize}_path) %></th>" }.join
504
+ }</tr></thead>
448
505
 
449
506
  <tbody>
450
507
  <% @#{table_name}.each do |#{obj_name}| %>
451
508
  <tr>#{"
452
509
  <td><%= link_to '⇛', #{path_obj_name}_path(#{obj_pk}), { class: 'big-arrow' } %></td>" if obj_pk}
453
- <% #{obj_name}.attributes.each do |k, val| %>
454
- <% next if (#{(obj_pk || []).inspect}.include?(k) && #{model_name}.column_for_attribute(k).type == :integer && !bts.key?(k)) ||
455
- ::Brick.config.metadata_columns.include?(k) || poly_cols.include?(k) || k.start_with?('_brfk_') || (k.start_with?('_br_') && (k.length == 63 || k.end_with?('_ct'))) %>
510
+ <% col_order.each do |col_name|
511
+ val = #{obj_name}.attributes[col_name] %>
456
512
  <td>
457
- <% if (bt = bts[k]) %>
458
- <%# binding.pry # Postgres column names are limited to 63 characters %>
513
+ <% if (bt = bts[col_name]) %>
459
514
  <% if bt[2] # Polymorphic?
460
515
  bt_class = #{obj_name}.send(\"#\{bt.first\}_type\")
461
516
  base_class = (::Brick.existing_stis[bt_class] || bt_class).constantize.base_class.name.underscore
@@ -464,6 +519,7 @@ function changeout(href, param, value, trimAfter) {
464
519
  send(\"#\{base_class\}_path\".to_sym, poly_id)) if poly_id %><%
465
520
  else
466
521
  bt_txt = (bt_class = bt[1].first.first).brick_descrip(
522
+ # 0..62 because Postgres column names are limited to 63 characters
467
523
  #{obj_name}, (descrips = @_brick_bt_descrip[bt.first][bt_class])[0..-2].map { |z| #{obj_name}.send(z.last[0..62]) }, (bt_id_col = descrips.last)
468
524
  )
469
525
  bt_id = #{obj_name}.send(*bt_id_col) if bt_id_col&.present? %>
@@ -488,20 +544,25 @@ function changeout(href, param, value, trimAfter) {
488
544
  <p style=\"color: green\"><%= notice %></p>#{"
489
545
  <select id=\"schema\">#{schema_options}</select>" if ::Brick.config.schema_behavior[:multitenant] && ::Brick.db_schemas.length > 1}
490
546
  <select id=\"tbl\">#{table_options}</select>
491
- <h1>#{model_name}: <%= (obj = @#{obj_name})&.brick_descrip || controller_name %></h1>
492
- <%= link_to '(See all #{obj_name.pluralize})', #{path_obj_name.pluralize}_path %>
547
+ <h1>#{model_name}: <%= (obj = @#{obj_name})&.brick_descrip || controller_name %></h1><%
548
+ if (relation = Brick.relations[#{model_name}.table_name])[:description] %><%=
549
+ relation.fetch(:description, nil) %><br><%
550
+ end
551
+ %><%= link_to '(See all #{obj_name.pluralize})', #{path_obj_name.pluralize}_path %>
493
552
  <% if obj %>
553
+ <br><br>
494
554
  <%= # path_options = [obj.#{pk}]
495
555
  # path_options << { '_brick_schema': } if
496
556
  # url = send(:#{model_name.underscore}_path, obj.#{pk})
497
557
  form_for(obj.becomes(#{model_name})) do |f| %>
498
558
  <table>
499
559
  <% has_fields = false
500
- @#{obj_name}.attributes.each do |k, val| %>
560
+ @#{obj_name}.attributes.each do |k, val|
561
+ col = #{model_name}.columns_hash[k] %>
501
562
  <tr>
502
563
  <% next if (#{(pk || []).inspect}.include?(k) && !bts.key?(k)) ||
503
564
  ::Brick.config.metadata_columns.include?(k) %>
504
- <th class=\"show-field\">
565
+ <th class=\"show-field\"<%= \" title = \\\"#\{col.comment}\\\"\".html_safe unless col.comment.blank? %>>
505
566
  <% has_fields = true
506
567
  if (bt = bts[k])
507
568
  # Add a final member in this array with descriptive options to be used in <select> drop-downs
@@ -546,7 +607,7 @@ function changeout(href, param, value, trimAfter) {
546
607
  <% else case #{model_name}.column_for_attribute(k).type
547
608
  when :string, :text %>
548
609
  <% if is_bcrypt?(val) # || .readonly? %>
549
- <%= hide_bcrypt(val) %>
610
+ <%= hide_bcrypt(val, 1000) %>
550
611
  <% else %>
551
612
  <div class=\"wide-input\"><%= f.text_field k.to_sym %></div>
552
613
  <% end %>
@@ -5,7 +5,7 @@ module Brick
5
5
  module VERSION
6
6
  MAJOR = 1
7
7
  MINOR = 0
8
- TINY = 34
8
+ TINY = 37
9
9
 
10
10
  # PRE is nil unless it's a pre-release (beta, RC, etc.)
11
11
  PRE = nil
data/lib/brick.rb CHANGED
@@ -1,25 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'active_record/version'
4
-
5
- # ActiveRecord before 4.0 didn't have #version
6
- unless ActiveRecord.respond_to?(:version)
7
- module ActiveRecord
8
- def self.version
9
- ::Gem::Version.new(ActiveRecord::VERSION::STRING)
10
- end
11
- end
12
- end
13
-
14
- # In ActiveSupport older than 5.0, the duplicable? test tries to new up a BigDecimal,
15
- # and Ruby 2.6 and later deprecates #new. This removes the warning from BigDecimal.
16
- require 'bigdecimal'
17
- if (ruby_version = ::Gem::Version.new(RUBY_VERSION)) >= ::Gem::Version.new('2.6') &&
18
- ActiveRecord.version < ::Gem::Version.new('5.0')
19
- def BigDecimal.new(*args, **kwargs)
20
- BigDecimal(*args, **kwargs)
21
- end
22
- end
3
+ require 'brick/compatibility'
23
4
 
24
5
  # Allow ActiveRecord 4.0 and 4.1 to work with newer Ruby (>= 2.4) by avoiding a "stack level too deep"
25
6
  # error when ActiveSupport tries to smarten up Numeric by messing with Fixnum and Bignum at the end of:
@@ -45,8 +26,8 @@ end
45
26
  require 'brick/util'
46
27
 
47
28
  # Allow ActiveRecord < 3.2 to work with Ruby 2.7 and later
48
- if ActiveRecord.version < ::Gem::Version.new('3.2') &&
49
- ruby_version >= ::Gem::Version.new('2.7')
29
+ if (ruby_version = ::Gem::Version.new(RUBY_VERSION)) >= ::Gem::Version.new('2.7') &&
30
+ ActiveRecord.version < ::Gem::Version.new('3.2')
50
31
  # Remove circular reference for "now"
51
32
  ::Brick::Util._patch_require(
52
33
  'active_support/values/time_zone.rb', '/activesupport',
@@ -132,7 +113,6 @@ module Brick
132
113
  associatives = hms.each_with_object({}) do |hmt, s|
133
114
  if (through = hmt.last.options[:through])
134
115
  skip_hms[through] = nil
135
- # binding.pry if hmt.first == :issue_issues
136
116
  s[hmt.first] = hms[through] # End up with a hash of HMT names pointing to join-table associations
137
117
  elsif hmt.last.inverse_of.nil?
138
118
  puts "SKIPPING #{hmt.last.name.inspect}"
@@ -18,7 +18,8 @@ module Brick
18
18
  desc 'Generates an initializer file for configuring Brick'
19
19
 
20
20
  def create_initializer_file
21
- unless File.exist?(filename = 'config/initializers/brick.rb')
21
+ is_brick_file = File.exist?(filename = 'config/initializers/brick.rb')
22
+ if is_brick_file && ::Brick.config.schema_behavior[:multitenant] || !is_brick_file
22
23
  # See if we can make suggestions for additional_references and polymorphic associations
23
24
  resembles_fks = Hash.new { |h, k| h[k] = [] }
24
25
  possible_polymorphics = {}
@@ -223,7 +224,10 @@ module Brick
223
224
  # # Database schema to use when analysing existing data, such as deriving a list of polymorphic classes in the case that
224
225
  # # it wasn't originally specified.
225
226
  # Brick.schema_behavior = :namespaced
226
- # Brick.schema_behavior = { multitenant: { schema_to_analyse: 'engineering' } }
227
+ #{Brick.config.schema_behavior ? "Brick.schema_behavior = { multitenant: { schema_to_analyse: #{
228
+ Brick.config.schema_behavior[:multitenant][:schema_to_analyse].inspect}" :
229
+ "# Brick.schema_behavior = { multitenant: { schema_to_analyse: 'engineering'"
230
+ } } }
227
231
 
228
232
  # # Polymorphic associations are set up by providing a model name and polymorphic association name#{poly}
229
233
 
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.34
4
+ version: 1.0.37
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-06-23 00:00:00.000000000 Z
11
+ date: 2022-06-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -214,6 +214,7 @@ extensions: []
214
214
  extra_rdoc_files: []
215
215
  files:
216
216
  - lib/brick.rb
217
+ - lib/brick/compatibility.rb
217
218
  - lib/brick/config.rb
218
219
  - lib/brick/extensions.rb
219
220
  - lib/brick/frameworks/cucumber.rb