brick 1.0.40 → 1.0.41

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: cf29d4af64b65c01ae68df45762b816403a1ebc0035e1221552f249ff3ba2ce9
4
- data.tar.gz: 076cdb672d7c2137cc74421467d72491e9ea89751fab32015f427158fc367b45
3
+ metadata.gz: 4455ebfde80fe8a4bd51f19438171abae2614e0740adba98ab39184952843a01
4
+ data.tar.gz: d5157748c37564156fc2f823cc3c4753b536491aa2cf81175683c8241fb2a2b9
5
5
  SHA512:
6
- metadata.gz: ce17038567ddd9d6d9d9dce6eb71fd50612d167b56351898ef9b3f9441d1a7ef3ee4ec3a57f3f24e613829e6c8a2f59517fc0d4e9266f11166b92821310b0c06
7
- data.tar.gz: 6a7bb38b009853594a8bf1ab28489bbc92d6300fcd0f8497c7950e81c6a62a4c6da2bd65840f93bd7afea40153727cb93914529120ecf9b0dceca39b21fef880
6
+ metadata.gz: 2a649c78c3e597004b36d6c33f1cd812a712fcfd561dfe94994de28e489de81508f9fea30b0896b4447c4ce0ffd0877fb8c5d7e20a34011212fd797a3cbd02ca
7
+ data.tar.gz: 58ecdc4acb12abb77169a8fda8cb8146fceaedeacdf77f1cec992008f98b05412e3a9e2f5b6a9721880caa710ba94792a187d3587248eea4d9946d309c91be56
data/lib/brick/config.rb CHANGED
@@ -205,5 +205,10 @@ module Brick
205
205
  def not_nullables=(columns)
206
206
  @mutex.synchronize { @not_nullables = columns }
207
207
  end
208
+
209
+ # Add a special page to show references to non-existent records ("orphans")
210
+ def add_orphans
211
+ true
212
+ end
208
213
  end
209
214
  end
@@ -415,14 +415,16 @@ module ActiveRecord
415
415
  hm_counts.each do |k, hm|
416
416
  associative = nil
417
417
  count_column = if hm.options[:through]
418
- fk_col = (associative = associatives[hm.name]).foreign_key
419
- hm.foreign_key
418
+ fk_col = (associative = associatives[hm.name])&.foreign_key
419
+ hm.foreign_key if fk_col
420
420
  else
421
421
  fk_col = hm.foreign_key
422
422
  poly_type = hm.inverse_of.foreign_type if hm.options.key?(:as)
423
423
  pk = hm.klass.primary_key
424
424
  (pk.is_a?(Array) ? pk.first : pk) || '*'
425
425
  end
426
+ next unless count_column # %%% Would be able to remove this when multiple foreign keys to same destination becomes bulletproof
427
+
426
428
  tbl_alias = "_br_#{hm.name}"
427
429
  pri_tbl = hm.active_record
428
430
  on_clause = []
@@ -565,7 +567,9 @@ Module.class_exec do
565
567
  full_class_name = +''
566
568
  full_class_name << "::#{self.name}" unless self == Object
567
569
  full_class_name << "::#{plural_class_name.underscore.singularize.camelize}"
568
- if (plural_class_name == 'BrickSwagger' || model = self.const_get(full_class_name))
570
+ if (plural_class_name == 'BrickSwagger' ||
571
+ (::Brick.config.add_orphans && plural_class_name == 'BrickGem') ||
572
+ model = self.const_get(full_class_name))
569
573
  # if it's a controller and no match or a model doesn't really use the same table name, eager load all models and try to find a model class of the right name.
570
574
  Object.send(:build_controller, self, class_name, plural_class_name, model, relations)
571
575
  end
@@ -897,6 +901,16 @@ class Object
897
901
  built_controller = Class.new(ActionController::Base) do |new_controller_class|
898
902
  (namespace || Object).const_set(class_name.to_sym, new_controller_class)
899
903
 
904
+ # Brick-specific pages
905
+ if plural_class_name == 'BrickGem'
906
+ self.define_method :orphans do
907
+ instance_variable_set(:@orphans, ::Brick.find_orphans(::Brick.set_db_schema(params)))
908
+ puts "BrickGemController #{action_name} #{params.inspect}"
909
+ # render inline: 'Brick gem!'
910
+ end
911
+ return [new_controller_class, code + ' # BrickGem controller!']
912
+ end
913
+
900
914
  unless (is_swagger = plural_class_name == 'BrickSwagger') # && request.format == :json)
901
915
  code << " def index\n"
902
916
  code << " @#{table_name} = #{model.name}#{pk&.present? ? ".order(#{pk.inspect})" : '.all'}\n"
@@ -1475,5 +1489,72 @@ module Brick
1475
1489
  end
1476
1490
  assoc_bt[:inverse] = assoc_hm
1477
1491
  end
1492
+
1493
+ # Locate orphaned records
1494
+ def find_orphans(multi_schema)
1495
+ is_default_schema = multi_schema&.==(Apartment.default_schema)
1496
+ relations.each_with_object([]) do |v, s|
1497
+ frn_tbl = v.first
1498
+ next if (relation = v.last).key?(:isView) || config.exclude_tables.include?(frn_tbl) ||
1499
+ !(for_pk = (relation[:pkey].values.first&.first))
1500
+
1501
+ is_default_frn_schema = !is_default_schema && multi_schema &&
1502
+ ((frn_parts = frn_tbl.split('.')).length > 1 && frn_parts.first)&.==(Apartment.default_schema)
1503
+ relation[:fks].select { |_k, assoc| assoc[:is_bt] }.each do |_k, bt|
1504
+ begin
1505
+ if bt.key?(:polymorphic)
1506
+ pri_pk = for_pk
1507
+ pri_tables = Brick.config.polymorphics["#{frn_tbl}.#{bt[:fk]}"]
1508
+ .each_with_object(Hash.new { |h, k| h[k] = [] }) do |pri_class, s|
1509
+ s[Object.const_get(pri_class).table_name] << pri_class
1510
+ end
1511
+ fk_id_col = "#{bt[:fk]}_id"
1512
+ fk_type_col = "#{bt[:fk]}_type"
1513
+ selects = []
1514
+ pri_tables.each do |pri_tbl, pri_types|
1515
+ # Skip if database is multitenant, we're not focused on "public", and the foreign and primary tables
1516
+ # are both in the "public" schema
1517
+ next if is_default_frn_schema &&
1518
+ ((pri_parts = pri_tbl&.split('.'))&.length > 1 && pri_parts.first)&.==(Apartment.default_schema)
1519
+
1520
+ selects << "SELECT '#{pri_tbl}' AS pri_tbl, frn.#{fk_type_col} AS pri_type, frn.#{fk_id_col} AS pri_id, frn.#{for_pk} AS frn_id
1521
+ FROM #{frn_tbl} AS frn
1522
+ LEFT OUTER JOIN #{pri_tbl} AS pri ON pri.#{pri_pk} = frn.#{fk_id_col}
1523
+ WHERE frn.#{fk_type_col} IN (#{
1524
+ pri_types.map { |pri_type| "'#{pri_type}'" }.join(', ')
1525
+ }) AND frn.#{bt[:fk]}_id IS NOT NULL AND pri.#{pri_pk} IS NULL\n"
1526
+ end
1527
+ ActiveRecord::Base.execute_sql(selects.join("UNION ALL\n")).each do |o|
1528
+ entry = [frn_tbl, o['frn_id'], o['pri_type'], o['pri_id'], fk_id_col]
1529
+ entry << o['pri_tbl'] if (pri_class = Object.const_get(o['pri_type'])) != pri_class.base_class
1530
+ s << entry
1531
+ end
1532
+ else
1533
+ # Skip if database is multitenant, we're not focused on "public", and the foreign and primary tables
1534
+ # are both in the "public" schema
1535
+ pri_tbl = bt.key?(:inverse_table) && bt[:inverse_table]
1536
+ next if is_default_frn_schema &&
1537
+ ((pri_parts = pri_tbl&.split('.'))&.length > 1 && pri_parts.first)&.==(Apartment.default_schema)
1538
+
1539
+ pri_pk = relations[pri_tbl].fetch(:pkey, nil)&.values&.first&.first ||
1540
+ _class_pk(pri_tbl, multi_schema)
1541
+ ActiveRecord::Base.execute_sql(
1542
+ "SELECT frn.#{bt[:fk]} AS pri_id, frn.#{for_pk} AS frn_id
1543
+ FROM #{frn_tbl} AS frn
1544
+ LEFT OUTER JOIN #{pri_tbl} AS pri ON pri.#{pri_pk} = frn.#{bt[:fk]}
1545
+ WHERE frn.#{bt[:fk]} IS NOT NULL AND pri.#{pri_pk} IS NULL
1546
+ ORDER BY 1, 2"
1547
+ ).each { |o| s << [frn_tbl, o['frn_id'], pri_tbl, o['pri_id'], bt[:fk]] }
1548
+ end
1549
+ rescue StandardError => err
1550
+ puts "Strange -- #{err.inspect}"
1551
+ end
1552
+ end
1553
+ end
1554
+ end
1555
+
1556
+ def _class_pk(dotted_name, multitenant)
1557
+ Object.const_get((multitenant ? [dotted_name.split('.').last] : dotted_name.split('.')).map { |nm| "::#{nm.singularize.camelize}" }.join).primary_key
1558
+ end
1478
1559
  end
1479
1560
  end
@@ -53,7 +53,9 @@ module Brick
53
53
  # Used by Rails 5.0 and above
54
54
  alias :_brick_template_exists? :template_exists?
55
55
  def template_exists?(*args, **options)
56
- _brick_template_exists?(*args, **options) || set_brick_model(args)
56
+ (::Brick.config.add_orphans && args.first == 'orphans') ||
57
+ _brick_template_exists?(*args, **options) ||
58
+ set_brick_model(args)
57
59
  end
58
60
 
59
61
  def set_brick_model(find_args)
@@ -88,44 +90,55 @@ module Brick
88
90
  unless (model_name = (
89
91
  @_brick_model ||
90
92
  (ActionView.version < ::Gem::Version.new('5.0') && args[1].is_a?(Array) ? set_brick_model(args) : nil)
91
- )&.name)
93
+ )&.name) ||
94
+ (is_orphans = ::Brick.config.add_orphans && args[0..1] == ['orphans', ['brick_gem']])
92
95
  return _brick_find_template(*args, **options)
93
96
  end
94
97
 
95
- pk = @_brick_model._brick_primary_key(::Brick.relations.fetch(model_name, nil))
96
- obj_name = model_name.split('::').last.underscore
97
- path_obj_name = model_name.underscore.tr('/', '_')
98
- table_name = obj_name.pluralize
99
- template_link = nil
100
- bts, hms, associatives = ::Brick.get_bts_and_hms(@_brick_model) # This gets BT and HM and also has_many :through (HMT)
101
- hms_columns = [] # Used for 'index'
102
- skip_klass_hms = ::Brick.config.skip_index_hms[model_name] || {}
103
- hms_headers = hms.each_with_object([]) do |hm, s|
104
- hm_stuff = [(hm_assoc = hm.last), "H#{hm_assoc.macro == :has_one ? 'O' : 'M'}#{'T' if hm_assoc.options[:through]}", (assoc_name = hm.first)]
105
- hm_fk_name = if hm_assoc.options[:through]
106
- associative = associatives[hm_assoc.name]
107
- "'#{associative.name}.#{associative.foreign_key}'"
108
- else
109
- hm_assoc.foreign_key
110
- end
111
- if args.first == 'index'
112
- hms_columns << if hm_assoc.macro == :has_many
113
- set_ct = if skip_klass_hms.key?(assoc_name.to_sym)
114
- 'nil'
115
- else
116
- # Postgres column names are limited to 63 characters
117
- attrib_name = "_br_#{assoc_name}_ct"[0..62]
118
- "#{obj_name}.#{attrib_name} || 0"
119
- end
98
+ unless is_orphans
99
+ pk = @_brick_model._brick_primary_key(::Brick.relations.fetch(model_name, nil))
100
+ obj_name = model_name.split('::').last.underscore
101
+ path_obj_name = model_name.underscore.tr('/', '_')
102
+ table_name = obj_name.pluralize
103
+ template_link = nil
104
+ bts, hms, associatives = ::Brick.get_bts_and_hms(@_brick_model) # This gets BT and HM and also has_many :through (HMT)
105
+ hms_columns = [] # Used for 'index'
106
+ skip_klass_hms = ::Brick.config.skip_index_hms[model_name] || {}
107
+ hms_headers = hms.each_with_object([]) do |hm, s|
108
+ hm_stuff = [(hm_assoc = hm.last), "H#{hm_assoc.macro == :has_one ? 'O' : 'M'}#{'T' if hm_assoc.options[:through]}", (assoc_name = hm.first)]
109
+ hm_fk_name = if hm_assoc.options[:through]
110
+ associative = associatives[hm_assoc.name]
111
+ associative && "'#{associative.name}.#{associative.foreign_key}'"
112
+ else
113
+ hm_assoc.foreign_key
114
+ end
115
+ if args.first == 'index'
116
+ hms_columns << if hm_assoc.macro == :has_many
117
+ set_ct = if skip_klass_hms.key?(assoc_name.to_sym)
118
+ 'nil'
119
+ else
120
+ # Postgres column names are limited to 63 characters
121
+ attrib_name = "_br_#{assoc_name}_ct"[0..62]
122
+ "#{obj_name}.#{attrib_name} || 0"
123
+ end
124
+ if hm_fk_name
120
125
  "<%= ct = #{set_ct}
121
126
  link_to \"#\{ct || 'View'\} #{assoc_name}\", #{hm_assoc.klass.name.underscore.tr('/', '_').pluralize}_path({ #{path_keys(hm_assoc, hm_fk_name, obj_name, pk)} }) unless ct&.zero? %>\n"
122
- else # has_one
127
+ else
128
+ "#{assoc_name}\n"
129
+ end
130
+ else # has_one
123
131
  "<%= obj = #{obj_name}.#{hm.first}; link_to(obj.brick_descrip, obj) if obj %>\n"
124
- end
125
- elsif args.first == 'show'
126
- hm_stuff << "<%= link_to '#{assoc_name}', #{hm_assoc.klass.name.underscore.tr('/', '_').pluralize}_path({ #{path_keys(hm_assoc, hm_fk_name, "@#{obj_name}", pk)} }) %>\n"
132
+ end
133
+ elsif args.first == 'show'
134
+ hm_stuff << if hm_fk_name
135
+ "<%= link_to '#{assoc_name}', #{hm_assoc.klass.name.underscore.tr('/', '_').pluralize}_path({ #{path_keys(hm_assoc, hm_fk_name, "@#{obj_name}", pk)} }) %>\n"
136
+ else
137
+ assoc_name
138
+ end
139
+ end
140
+ s << hm_stuff
127
141
  end
128
- s << hm_stuff
129
142
  end
130
143
 
131
144
  schema_options = ::Brick.db_schemas.keys.each_with_object(+'') { |v, s| s << "<option value=\"#{v}\">#{v}</option>" }.html_safe
@@ -140,6 +153,7 @@ module Brick
140
153
  end.sort.each_with_object(+'') do |v, s|
141
154
  s << "<option value=\"#{v.underscore.gsub('.', '/').pluralize}\">#{v}</option>"
142
155
  end.html_safe
156
+ table_options << '<option value="brick_orphans">(Orphans)</option>'.html_safe if is_orphans
143
157
  css = +"<style>
144
158
  #dropper {
145
159
  background-color: #eee;
@@ -507,7 +521,13 @@ if (headerTop) {
507
521
  %></th><%
508
522
  end
509
523
  # Consider getting the name from the association -- h.first.name -- if a more \"friendly\" alias should be used for a screwy table name
510
- %>#{hms_headers.map { |h| "<th>#{h[1]} <%= link_to('#{h[2]}', #{h.first.klass.name.underscore.tr('/', '_').pluralize}_path) %></th>" }.join
524
+ %>#{hms_headers.map do |h|
525
+ if h.first.options[:through] && !h.first.through_reflection
526
+ "<th>#{h[1]} #{h[2]} %></th>"
527
+ else
528
+ "<th>#{h[1]} <%= link_to('#{h[2]}', #{h.first.klass.name.underscore.tr('/', '_').pluralize}_path) %></th>"
529
+ end
530
+ end.join
511
531
  }</tr></thead>
512
532
 
513
533
  <tbody>
@@ -547,6 +567,22 @@ if (headerTop) {
547
567
 
548
568
  #{"<hr><%= link_to \"New #{obj_name}\", new_#{path_obj_name}_path %>" unless @_brick_model.is_view?}
549
569
  #{script}"
570
+ when 'orphans'
571
+ if is_orphans
572
+ "#{css}
573
+ <p style=\"color: green\"><%= notice %></p>#{"
574
+ <select id=\"schema\">#{schema_options}</select>" if ::Brick.config.schema_behavior[:multitenant] && ::Brick.db_schemas.length > 1}
575
+ <select id=\"tbl\">#{table_options}</select>
576
+ <h1>Orphans<%= \" for #\{}\" if false %></h1>
577
+ <% @orphans.each do |o|
578
+ via = \" (via #\{o[4]})\" unless \"#\{o[2].split('.').last.underscore.singularize}_id\" == o[4] %>
579
+ <a href=\"/<%= o[0].split('.').last %>/<%= o[1] %>\">
580
+ <%= \"#\{o[0]} #\{o[1]} refers#\{via} to non-existent #\{o[2]} #\{o[3]}#\{\" (in table \\\"#\{o[5]}\\\")\" if o[5]}\" %>
581
+ </a><br>
582
+ <% end %>
583
+ #{script}"
584
+ end
585
+
550
586
  when 'show', 'update'
551
587
  "#{css}
552
588
  <p style=\"color: green\"><%= notice %></p>#{"
@@ -646,6 +682,8 @@ end
646
682
  <% end %>
647
683
 
648
684
  #{hms_headers.each_with_object(+'') do |hm, s|
685
+ next if hm.first.options[:through] && !hm.first.through_reflection
686
+
649
687
  if (pk = hm.first.klass.primary_key)
650
688
  hm_singular_name = (hm_name = hm.first.name.to_s).singularize.underscore
651
689
  obj_pk = (pk.is_a?(Array) ? pk : [pk]).each_with_object([]) { |pk_part, s| s << "#{hm_singular_name}.#{pk_part}" }.join(', ')
@@ -4,53 +4,25 @@ if Object.const_defined?('::Rake::TaskManager')
4
4
  namespace :brick do
5
5
  desc 'Find any seemingly-orphaned records'
6
6
  task orphans: :environment do
7
- def class_pk(dotted_name, multitenant)
8
- Object.const_get((multitenant ? [dotted_name.split('.').last] : dotted_name.split('.')).map { |nm| "::#{nm.singularize.camelize}" }.join).primary_key
9
- end
10
-
11
7
  schema_list = ((multi = ::Brick.config.schema_behavior[:multitenant]) && ::Brick.db_schemas.keys.sort) || []
12
- if schema_list.length > 1
13
- require 'fancy_gets'
14
- include FancyGets
15
- schema = gets_list(
16
- list: schema_list,
17
- chosen: multi[:schema_to_analyse]
18
- )
19
- elsif schema_list.length.positive?
20
- schema = schema_list.first
21
- end
8
+ schema = if schema_list.length == 1
9
+ schema_list.first
10
+ elsif schema_list.length.positive?
11
+ require 'fancy_gets'
12
+ include FancyGets
13
+ gets_list(list: schema_list, chosen: multi[:schema_to_analyse])
14
+ end
22
15
  ActiveRecord::Base.execute_sql("SET SEARCH_PATH = ?", schema) if schema
23
- orphans = +''
24
- ::Brick.relations.each do |k, v|
25
- next if v.key?(:isView) || ::Brick.config.exclude_tables.include?(k) ||
26
- !(pri_pk = v[:pkey].values.first&.first) ||
27
- !(pri_pk = class_pk(k, multi))
28
- v[:fks].each do |k1, v1|
29
- next if v1[:is_bt] ||
30
- !(for_rel = ::Brick.relations.fetch(v1[:inverse_table], nil)) ||
31
- v1[:inverse]&.key?(:polymorphic) ||
32
- !(for_pk = for_rel.fetch(:pkey, nil)&.values&.first&.first) ||
33
- !(for_pk = class_pk(v1[:inverse_table], multi))
34
- begin
35
- ActiveRecord::Base.execute_sql(
36
- "SELECT DISTINCT frn.#{v1[:fk]} AS pri_id, frn.#{for_pk} AS fk_id
37
- FROM #{v1[:inverse_table]} AS frn
38
- LEFT OUTER JOIN #{k} AS pri ON pri.#{pri_pk} = frn.#{v1[:fk]}
39
- WHERE frn.#{v1[:fk]} IS NOT NULL AND pri.#{pri_pk} IS NULL
40
- ORDER BY 1, 2"
41
- ).each do |o|
42
- orphans << "#{v1[:inverse_table]} #{o['fk_id']} refers to non-existant #{k} #{o['pri_id']}\n"
43
- end
44
- rescue StandardError => err
45
- puts "Strange -- #{err.inspect}"
46
- end
47
- end
48
- end
49
- puts "For #{schema}:\n#{'=' * (schema.length + 5)}" if schema
50
- if orphans.blank?
16
+ orphans = ::Brick.find_orphans(schema)
17
+ puts "Orphans in #{schema}:\n#{'=' * (schema.length + 12)}" if schema
18
+ if orphans.empty?
51
19
  puts "No orphans!"
52
20
  else
53
- print orphans
21
+ orphans.each do |o|
22
+ via = " (via #{o[4]})" unless "#{o[2].split('.').last.underscore.singularize}_id" == o[4]
23
+ puts "#{o[0]} #{o[1]} refers#{via} to non-existent #{o[2]} #{o[3]}#{" (in table \"#{o[5]}\")" if o[5]}"
24
+ end
25
+ puts
54
26
  end
55
27
  end
56
28
  end
@@ -5,7 +5,7 @@ module Brick
5
5
  module VERSION
6
6
  MAJOR = 1
7
7
  MINOR = 0
8
- TINY = 40
8
+ TINY = 41
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
@@ -128,7 +128,10 @@ module Brick
128
128
 
129
129
  def set_db_schema(params)
130
130
  schema = params['_brick_schema'] || 'public'
131
- ActiveRecord::Base.execute_sql("SET SEARCH_PATH = ?;", schema) if schema && ::Brick.db_schemas&.include?(schema)
131
+ if schema && ::Brick.db_schemas&.include?(schema)
132
+ ActiveRecord::Base.execute_sql("SET SEARCH_PATH = ?;", schema)
133
+ schema
134
+ end
132
135
  end
133
136
 
134
137
  # All tables and views (what Postgres calls "relations" including column and foreign key info)
@@ -457,6 +460,9 @@ In config/initializers/brick.rb appropriate entries would look something like:
457
460
  send(:resources, controller_name.to_sym, **options)
458
461
  end
459
462
  end
463
+ if ::Brick.config.add_orphans && instance_variable_get(:@set).named_routes.names.exclude?(:brick_orphans)
464
+ get('/brick_orphans', to: 'brick_gem#orphans', as: 'brick_orphans')
465
+ end
460
466
  end
461
467
  send(:get, '/api-docs/v1/swagger.json', { to: 'brick_swagger#index' }) if Object.const_defined?('Rswag::Ui')
462
468
  end
@@ -209,7 +209,7 @@ module Brick
209
209
  # # Specify STI subclasses either directly by name or as a general module prefix that should always relate to a specific
210
210
  # # parent STI class. The prefixed :: here for these examples is mandatory. Also having a suffixed :: means instead of
211
211
  # # a class reference, this is for a general namespace reference. So in this case requests for, say, either of the
212
- # # non-existant classes Animals::Cat or Animals::Goat (or anything else with the module prefix of \"Animals::\" would
212
+ # # non-existent classes Animals::Cat or Animals::Goat (or anything else with the module prefix of \"Animals::\" would
213
213
  # # build a model that inherits from Animal. And a request specifically for the class Snake would build a new model
214
214
  # # that inherits from Reptile, and no other request would do this -- only specifically for Snake. The ending ::
215
215
  # # indicates that it's a module prefix instead of a specific class name.
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.40
4
+ version: 1.0.41
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-07-02 00:00:00.000000000 Z
11
+ date: 2022-07-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord