brick 1.0.235 → 1.0.236

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: dbee410a881406dbcec60714bf2688d0cbc4aef0c89a68888ce9f2401e0005dd
4
- data.tar.gz: b1a06757052b4130080b6a8762b1d7f8522f551956850bb8c2fe6655260380eb
3
+ metadata.gz: 8397091edab4be1edd1e61eb4be3284a8c169a3207f87e92227b84d07413d241
4
+ data.tar.gz: 2ffaef636cfba92e38bf9330f04a5bd65f39eb06d62e002e5227f7261b126494
5
5
  SHA512:
6
- metadata.gz: 2eca4cb00874a367159483ac23a6a03d273d5b5bd54913272f99a7ffefc26e2bbaced2a52b9df624320912e9b70445a432dd4694e5ccc673cb60187633e87d91
7
- data.tar.gz: 381d498e42a473cf92cd556b843c59eb08618b0c8f2e61808689a4f1b4c2d5a0e0078d171d64b055cedca78d81bf5fbcfa73eff5268ca3d9d56076ec1c505299
6
+ metadata.gz: 38d24e9e8ae60a63f6755bb5e0854880df019ce4004d3e8962c8a47cfc80bb23fcba576216e9cedf7560f37b458ce47e651ccaa206b0e92844519e2a932d7c7e
7
+ data.tar.gz: 4f33bd865494dcd1855204bd5c307f8b2fc70485bd8ce5c9fd79708df638ff0f715d44755087a0c8230589dd3679d238dfdaeea8807dc14cf4a658fae21ffa7d
@@ -70,7 +70,8 @@ module ActiveRecord
70
70
  false
71
71
  end
72
72
 
73
- def real_model(params)
73
+ # Accommodate STI
74
+ def find_real_model(params)
74
75
  if params && ((sub_name = params.fetch(inheritance_column, nil)).present? ||
75
76
  (sub_name = params[name.underscore]&.fetch(inheritance_column, nil)))
76
77
  sub_name = sub_name.first if sub_name.is_a?(Array) # Support the params style that gets returned from #_brick_querying
@@ -83,10 +84,9 @@ module ActiveRecord
83
84
  end
84
85
  end
85
86
 
86
- # Accommodate STI
87
87
  def real_singular(params)
88
- real_model = real_model(params)
89
- [real_model, real_model.name.underscore.split('/').last]
88
+ real_model = find_real_model(params)
89
+ [real_model, real_model.name.underscore.tr('/', '_')]
90
90
  end
91
91
 
92
92
  def json_column?(col)
@@ -961,8 +961,12 @@ module ActiveRecord
961
961
  fk_col = (inv = hm.inverse_of)&.foreign_key || hm.foreign_key
962
962
  # %%% Might only need hm.type and not the first part :)
963
963
  poly_type = inv&.foreign_type || hm.type if hm.options.key?(:as)
964
- pk = hm.klass.primary_key
965
- (pk.is_a?(Array) ? pk.first : pk) || '*'
964
+ if hm.macro == :has_and_belongs_to_many
965
+ '*'
966
+ else
967
+ pk = hm.klass.primary_key
968
+ (pk.is_a?(Array) ? pk.first : pk) || '*'
969
+ end
966
970
  end
967
971
  next unless count_column # %%% Would be able to remove this when multiple foreign keys to same destination becomes bulletproof
968
972
 
@@ -1830,7 +1834,7 @@ class Object
1830
1834
  def import(options={}, &block)
1831
1835
  unless self.__elasticsearch__.index_exists?
1832
1836
  self.__elasticsearch__.create_index!
1833
- ::Brick.elasticsearch_existings[self.table_name] = self.table_name.tr('.', '-').pluralize
1837
+ ::Brick.elasticsearch_existings[self.table_name.tr('.', '-').pluralize] = self.table_name
1834
1838
  end
1835
1839
  _original_import(options={}, &block)
1836
1840
  end
@@ -1867,7 +1871,7 @@ class Object
1867
1871
  end
1868
1872
  rescue Elastic::Transport::Transport::Errors::NotFound => e
1869
1873
  self.__elasticsearch__.create_index! if @_brick_es_crud.index('i')
1870
- ::Brick.elasticsearch_existings[self.table_name] = self.table_name.tr('.', '-').pluralize
1874
+ ::Brick.elasticsearch_existings[self.table_name.tr('.', '-').pluralize] = self.table_name
1871
1875
  []
1872
1876
  end
1873
1877
  end
@@ -2040,12 +2044,12 @@ class Object
2040
2044
  (anaf.is_a?(Array) ? anaf.include?(assoc_name) : anaf == assoc_name)
2041
2045
  macro
2042
2046
  end
2043
- # Figure out if we need to specially call out the class_name and/or foreign key
2044
- # (and if either of those then definitely also a specific inverse_of)
2045
2047
  if (singular_table_parts = singular_table_name.split('.')).length > 1 &&
2046
2048
  ::Brick.config.schema_behavior[:multitenant] && singular_table_parts.first == 'public'
2047
2049
  singular_table_parts.shift
2048
2050
  end
2051
+ # Figure out if we need to specially call out the class_name and/or foreign key
2052
+ # (and if either of those then definitely also a specific inverse_of)
2049
2053
  if need_class_name
2050
2054
  options[:class_name] = "::#{assoc[:primary_class]&.name || ::Brick.relations[inverse_table][:class_name]}"
2051
2055
  end
@@ -2441,7 +2445,7 @@ class Object
2441
2445
  return
2442
2446
  end
2443
2447
 
2444
- real_model = model.real_model(params)
2448
+ real_model = model.find_real_model(params)
2445
2449
 
2446
2450
  if request.format == :csv # Asking for a template?
2447
2451
  require 'csv'
@@ -2520,9 +2524,10 @@ class Object
2520
2524
  end
2521
2525
  end
2522
2526
  ar_select = ar_relation.respond_to?(:_select!) ? ar_relation.dup._select!(*selects, *counts) : ar_relation.select(selects + counts)
2527
+ # %%% should this be real_singular_name.pluralize?
2523
2528
  instance_variable_set("@#{plural_table_name}".to_sym, ar_select)
2524
2529
  @_lookup_context.instance_variable_set(:@_brick_is_postgres, true) if is_postgres
2525
- table_name_no_schema = singular_table_name.pluralize
2530
+ table_name_no_schema = real_model.name.underscore.split('/').last.pluralize # %%% hmmm ...
2526
2531
  if namespace && (idx = lookup_context.prefixes.index(table_name_no_schema))
2527
2532
  lookup_context.prefixes[idx] = "#{namespace.name.underscore}/#{lookup_context.prefixes[idx]}"
2528
2533
  end
@@ -2538,6 +2543,12 @@ class Object
2538
2543
  @_brick_erd = params['_brick_erd']&.to_i
2539
2544
  add_csp_hash
2540
2545
  end
2546
+
2547
+ _, order_by_txt = model._brick_calculate_ordering(default_ordering(table_name, pk, true)) if pk
2548
+ code << " def index\n"
2549
+ code << " @#{plural_table_name} = #{model.name}#{pk&.present? ? ".order(#{order_by_txt.join(', ')})" : '.all'}\n"
2550
+ code << " @#{plural_table_name}._brick_querying(params, brick_col_names: true)\n"
2551
+ code << " end\n"
2541
2552
  end
2542
2553
 
2543
2554
  unless is_openapi || is_avo # Normal controller (non-API)
@@ -2561,12 +2572,6 @@ class Object
2561
2572
  end
2562
2573
  end
2563
2574
 
2564
- _, order_by_txt = model._brick_calculate_ordering(default_ordering(table_name, pk, true)) if pk
2565
- code << " def index\n"
2566
- code << " @#{plural_table_name} = #{model.name}#{pk&.present? ? ".order(#{order_by_txt.join(', ')})" : '.all'}\n"
2567
- code << " @#{plural_table_name}._brick_querying(params, brick_col_names: true)\n"
2568
- code << " end\n"
2569
-
2570
2575
  # ----------------------------------------------------------------------------------
2571
2576
 
2572
2577
  if pk.present?
@@ -2576,8 +2581,8 @@ class Object
2576
2581
  find_obj = "find_#{singular_table_name}"
2577
2582
  self.define_method :show do
2578
2583
  _schema, @_is_show_schema_list = ::Brick.set_db_schema(params)
2579
- _, singular_table_name = model.real_singular(params)
2580
- instance_variable_set("@#{singular_table_name}".to_sym, send(find_obj))
2584
+ _, real_singular_table_name = model.real_singular(params)
2585
+ instance_variable_set("@#{real_singular_table_name}".to_sym, send(find_obj))
2581
2586
  add_csp_hash("'unsafe-inline'")
2582
2587
  end
2583
2588
  end
@@ -2595,7 +2600,7 @@ class Object
2595
2600
  send(params_name_sym)
2596
2601
  rescue
2597
2602
  end
2598
- real_model, singular_table_name = model.real_singular(params)
2603
+ real_model, real_singular_table_name = model.real_singular(params)
2599
2604
  new_params ||= real_model.attribute_names.each_with_object({}) do |a, s|
2600
2605
  if (val = params["__#{a}"])
2601
2606
  # val = case new_obj.class.column_for_attribute(a).type
@@ -2613,7 +2618,7 @@ class Object
2613
2618
  new_obj.send("#{k}=", ::ActiveStorage::Filename.new('')) if v.is_a?(::ActiveStorage::Filename) && !v.instance_variable_get(:@filename)
2614
2619
  end if Object.const_defined?('ActiveStorage')
2615
2620
  end
2616
- instance_variable_set("@#{singular_table_name}".to_sym, new_obj)
2621
+ instance_variable_set("@#{real_singular_table_name}".to_sym, new_obj)
2617
2622
  add_csp_hash
2618
2623
  end
2619
2624
 
@@ -2645,9 +2650,9 @@ class Object
2645
2650
  model.__elasticsearch__.search(q)
2646
2651
  rescue Elastic::Transport::Transport::Errors::NotFound => e
2647
2652
  if @_brick_es_crud.index('i')
2648
- self.__elasticsearch__.create_index!
2653
+ model.__elasticsearch__.create_index!
2649
2654
  # model.import
2650
- ::Brick.elasticsearch_existings[self.table_name] = self.table_name.tr('.', '-').pluralize
2655
+ ::Brick.elasticsearch_existings[model.table_name.tr('.', '-').pluralize] = model.table_name
2651
2656
  model.__elasticsearch__.search(q)
2652
2657
  else
2653
2658
  []
@@ -2656,8 +2661,7 @@ class Object
2656
2661
  end
2657
2662
  render json: { result: es_result }
2658
2663
  else
2659
- real_model = model.real_model(params)
2660
- singular_table_name = real_model.name.underscore.split('/').last
2664
+ real_model, real_singular_table_name = model.real_singular(params)
2661
2665
  created_obj = model.send(:new, send(params_name_sym))
2662
2666
  if created_obj.respond_to?(inh_col = model.inheritance_column) && created_obj.send(inh_col) == ''
2663
2667
  created_obj.send("#{inh_col}=", model.name)
@@ -2665,12 +2669,12 @@ class Object
2665
2669
  created_obj.save
2666
2670
  @_lookup_context.instance_variable_set(:@_brick_model, real_model)
2667
2671
  if created_obj.errors.empty?
2668
- instance_variable_set("@#{singular_table_name}".to_sym, created_obj)
2672
+ instance_variable_set("@#{real_singular_table_name}".to_sym, created_obj)
2669
2673
  @_lookup_context.instance_variable_set(:@_brick_is_postgres, true) if is_postgres
2670
2674
  index
2671
2675
  render :index
2672
2676
  else # Surface errors to the user in a flash message
2673
- instance_variable_set("@#{singular_table_name}".to_sym, created_obj)
2677
+ instance_variable_set("@#{real_singular_table_name}".to_sym, created_obj)
2674
2678
  flash.now.alert = (created_obj.errors.errors.map { |err| "<b>#{err.attribute}</b> #{err.message}" }.join(', '))
2675
2679
  new
2676
2680
  render :new
@@ -2689,8 +2693,8 @@ class Object
2689
2693
  code << " end\n"
2690
2694
  self.define_method :edit do
2691
2695
  _schema, @_is_show_schema_list = ::Brick.set_db_schema(params)
2692
- _, singular_table_name = model.real_singular(params)
2693
- instance_variable_set("@#{singular_table_name}".to_sym, send(find_obj))
2696
+ _, real_singular_table_name = model.real_singular(params)
2697
+ instance_variable_set("@#{real_singular_table_name}".to_sym, send(find_obj))
2694
2698
  add_csp_hash
2695
2699
  end
2696
2700
 
@@ -2717,8 +2721,8 @@ class Object
2717
2721
  # return
2718
2722
  end
2719
2723
 
2720
- _, singular_table_name = model.real_singular(params)
2721
- instance_variable_set("@#{singular_table_name}".to_sym, (obj = send(find_obj)))
2724
+ _, real_singular_table_name = model.real_singular(params)
2725
+ instance_variable_set("@#{real_singular_table_name}".to_sym, (obj = send(find_obj)))
2722
2726
  upd_params = send(params_name_sym)
2723
2727
  json_overrides = ::Brick.config.json_columns&.fetch(table_name, nil)
2724
2728
  if model.respond_to?(:devise_modules)
@@ -2746,7 +2750,8 @@ class Object
2746
2750
  end
2747
2751
  # Do not clear out a has_many_attached field if it already has an entry and nothing is supplied
2748
2752
  hoa, hma, rtans = model._activestorage_actiontext_fields
2749
- all_params = params[singular_table_name]
2753
+ # %%% does this work with STI?
2754
+ all_params = params[real_singular_table_name]
2750
2755
  hma.each do |hma_field|
2751
2756
  if upd_hash.fetch(hma_field) == [''] && # No new attachments...
2752
2757
  all_params&.fetch("_brick_attached_#{hma_field}", nil) # ...and there is something existing
@@ -626,7 +626,7 @@ window.addEventListener(\"popstate\", linkSchemas);
626
626
  # Only CUD stuff has create / update / destroy
627
627
  (!model.is_view? && ['new', 'create', 'edit', 'update', 'destroy'].include?(find_args.first))
628
628
  )
629
- @_brick_model = model.real_model(params)
629
+ @_brick_model = model.find_real_model(params)
630
630
  end
631
631
  rescue
632
632
  end
@@ -1344,8 +1344,8 @@ end
1344
1344
  <head>
1345
1345
  #{css}
1346
1346
  <title><%=
1347
- base_model = (model = (obj = @#{obj_name}).class).base_class
1348
- see_all_path = send(\"#\{base_model._brick_index}_path\")
1347
+ if (model = (obj = @#{obj_name})&.class || @lookup_context&.instance_variable_get(:@_brick_model))
1348
+ see_all_path = send(\"#\{(base_model = model.base_class)._brick_index}_path\")
1349
1349
  #{(inh_col = @_brick_model.inheritance_column).present? &&
1350
1350
  " if obj.respond_to?(:#{inh_col}) && (model_name = @#{obj_name}.#{inh_col}) &&
1351
1351
  !model_name.is_a?(Numeric) && model_name != base_model.name
@@ -26,10 +26,13 @@ module Brick
26
26
  # Auto-create when there is a missing index
27
27
  alias _original_method_missing method_missing
28
28
  def method_missing(name, *args, &block)
29
+ return if name == :transport # Avoid infinite loop if Elasticsearch isn't yet initialized
30
+
29
31
  _original_method_missing(name, *args, &block)
30
32
  rescue Elastic::Transport::Transport::Errors::NotFound => e
31
33
  if (missing_index = args.last&.fetch(:defined_params, nil)&.fetch(:index, nil)) &&
32
- ::Brick.elasticsearch_models&.fetch(missing_index, nil)&.include?('i')
34
+ (es_table_name = ::Brick.elasticsearch_possible&.fetch(missing_index, nil)) &&
35
+ ::Brick.elasticsearch_models&.fetch(es_table_name, nil)&.include?('i')
33
36
  self.indices.create({ index: missing_index,
34
37
  body: { settings: {}, mappings: { properties: {} } } })
35
38
  puts "Auto-creating missing index \"#{missing_index}\""
@@ -40,9 +43,10 @@ module Brick
40
43
  end
41
44
  end
42
45
  end
43
- if ::Elasticsearch.const_defined?('Model')
44
- # By setting the environment variable ELASTICSEARCH_URL then you can specify an Elasticsearch/Opensearch host
45
- host = (client = ::Elasticsearch::Model.client).transport.hosts.first
46
+ if ::Elasticsearch.const_defined?('Model') &&
47
+ # By setting the environment variable ELASTICSEARCH_URL then you can specify an Elasticsearch/Opensearch
48
+ # host that is picked up here
49
+ (host = (client = ::Elasticsearch::Model.client).transport&.hosts&.first)
46
50
  es_uri = URI.parse("#{host[:protocol]}://#{host[:host]}:#{host[:port]}")
47
51
  es_uri = nil if es_uri.to_s == 'http://localhost:9200'
48
52
  begin
@@ -513,7 +517,7 @@ ORDER BY 1, 2, c.internal_column_id, acc.position"
513
517
  end
514
518
  end
515
519
 
516
- if ems = ::Brick.elasticsearch_models # ['comments']
520
+ if (ems = ::Brick.elasticsearch_models)
517
521
  access = case ems
518
522
  when Hash, String # Hash is a list of resource names and ES permissions such as 'r' or 'icr'
519
523
  ems
@@ -544,6 +548,9 @@ ORDER BY 1, 2, c.internal_column_id, acc.position"
544
548
  next if rel.first.is_a?(Symbol)
545
549
 
546
550
  perms = rel.last.fetch(:isView, nil) ? access.tr('cud', '') : access
551
+ unless ::Brick.elasticsearch_existings[es_index = rel.first.tr('.', '-').pluralize]
552
+ (::Brick.elasticsearch_possible ||= {})[es_index] = rel.first
553
+ end
547
554
  s[rel.first] = perms
548
555
  end
549
556
  else # or there are specific permissions for each resource, so find the matching indexes
@@ -5,7 +5,7 @@ module Brick
5
5
  module VERSION
6
6
  MAJOR = 1
7
7
  MINOR = 0
8
- TINY = 235
8
+ TINY = 236
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
@@ -111,7 +111,7 @@ module Brick
111
111
  :established_drf,
112
112
  :is_oracle, :is_eager_loading, :auto_models, :initializer_loaded,
113
113
  :table_name_lookup,
114
- :elasticsearch_models, :elasticsearch_existings,
114
+ :elasticsearch_models, :elasticsearch_existings, :elasticsearch_possible,
115
115
  :routes_done
116
116
  ::Brick.auto_models = []
117
117
 
@@ -38,7 +38,6 @@ module Brick
38
38
  existing_models = ActiveRecord::Base.descendants.each_with_object({}) do |m, s|
39
39
  s[m.table_name] = SeedModel.new(m.table_name, m, false) if !m.abstract_class? && !m.is_view? && m.table_exists?
40
40
  end
41
-
42
41
  models = (existing_models.values +
43
42
  # ... then add models which can be auto-built by Brick
44
43
  relations.reject do |k, v|
@@ -57,7 +56,6 @@ module Brick
57
56
  end
58
57
  end
59
58
  end
60
-
61
59
  seeds = +'# Seeds file for '
62
60
  if (arbc = ActiveRecord::Base.connection).respond_to?(:current_database) # SQLite3 can't do this!
63
61
  seeds << "#{arbc.current_database}:\n"
@@ -124,23 +122,22 @@ module Brick
124
122
  end
125
123
  end
126
124
  schema = if (tbl_parts = tbl.split('.')).length > 1
127
- if tbl_parts.first == (::Brick.default_schema || 'public')
128
- tbl_parts.shift
129
- nil
130
- else
131
- tbl_parts.first
132
- end
133
- end
125
+ if tbl_parts.first == (::Brick.default_schema || 'public')
126
+ tbl_parts.shift
127
+ nil
128
+ else
129
+ tbl_parts.first
130
+ end
131
+ end
132
+
133
+ # # Had considered doing this for non-Airtable:
134
+ # # For the moment we're skipping polymorphics
135
+ # fkeys = klass.reflect_on_all_associations.select { |a| a.belongs_to? && !a.polymorphic? }.map do |fk|
136
+ # { fk: fk.foreign_key, assoc_name: fk.name.to_s, inverse_table: fk.table_name }
137
+ # end
138
+ # For the moment we're skipping polymorphics
139
+ fkeys = relation[:fks].values.select { |assoc| assoc[:is_bt] && !assoc[:polymorphic] }
134
140
 
135
- # %%% For the moment we're skipping polymorphics
136
- fkeys = if is_airtable
137
- tbl = tbl.singularize
138
- relation[:fks]&.values&.select { |assoc| assoc[:is_bt] && !assoc[:polymorphic] }
139
- else
140
- klass.reflect_on_all_associations.select { |a| a.belongs_to? && !a.polymorphic? }.map do |fk|
141
- { fk: fk.foreign_key, assoc_name: fk.name.to_s, inverse_table: fk.table_name }
142
- end
143
- end
144
141
  # Refer to this table name as a symbol or dotted string as appropriate
145
142
  # tbl_code = tbl_parts.length == 1 ? ":#{tbl_parts.first}" : "'#{tbl}'"
146
143
 
@@ -205,7 +202,7 @@ module Brick
205
202
  if fk
206
203
  fk_val = if is_airtable
207
204
  # The (3..-1) is to take off the "rec___" prefix
208
- obj.attributes_before_type_cast[fk[:assoc_name]]&.first&.[](3..-1) if is_airtable
205
+ obj.attributes_before_type_cast[fk[:assoc_name]]&.first&.[](3..-1)
209
206
  else
210
207
  brick_escape(val)
211
208
  end
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.235
4
+ version: 1.0.236
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lorin Thwaits
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-03-20 00:00:00.000000000 Z
11
+ date: 2025-04-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -261,7 +261,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
261
261
  - !ruby/object:Gem::Version
262
262
  version: 1.3.6
263
263
  requirements: []
264
- rubygems_version: 3.4.19
264
+ rubygems_version: 3.2.33
265
265
  signing_key:
266
266
  specification_version: 4
267
267
  summary: Create a Rails app from data alone