brick 1.0.122 → 1.0.124

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: b1f047f700bc850e0e54210cd9669e2877c2d770010f42c82b7f2616ad14f542
4
- data.tar.gz: e89b2be75f7d961b24681b4e6c5aeb8beedef51e2537759f93a68baff1787e60
3
+ metadata.gz: 44fce70a53b4467d019ca42a9826f44a4849d472dcbfc2fe324f961708b70a18
4
+ data.tar.gz: 2674709f203786560b41c1bf1e2062336cf88282d168848303e9920b398662e3
5
5
  SHA512:
6
- metadata.gz: 54418f3b20260bea82b912383038fce3a019a6daf85e56714a1eb2331c7aa130c44706d64e8d1c86502d9ed7c6f7ece730b8a3d467fbe77ee3e699f8e2eb1586
7
- data.tar.gz: baf068daf69952fd2235b14abddd93420b73984912eef5da6ffc33699db124058b2e6a093d9984d2fe31abbe620e6d51d5bdbecc5cf23297f6c31b4d4450ed71
6
+ metadata.gz: 337760a0382fd37a64026a07d80e708f9f475f73e8ca420d05341b731c977ab9153556803f10314a4851730e28a22ce4847705e2d8ad81121a8f33736f505f12
7
+ data.tar.gz: 04a1e5ec1cc503173da16be708d611f9fb1dd6f3965e6e848dfd1e310f3e1c94b396c8e693982d8f3c3589b5d8ffbfee70fd52593918e12ecd8309c8e110b4c5
@@ -638,6 +638,7 @@ module ActiveRecord
638
638
  # Add derived table JOIN for the has_many counts
639
639
  nix = []
640
640
  klass._br_hm_counts.each do |k, hm|
641
+ num_bt_things = 0
641
642
  count_column = if hm.options[:through]
642
643
  # Build the chain of JOINs going to the final destination HMT table
643
644
  # (Usually just one JOIN, but could be many.)
@@ -668,6 +669,8 @@ module ActiveRecord
668
669
  from_clause << if (src_ref = a.source_reflection).macro == :belongs_to
669
670
  nm = hmt_assoc.source_reflection.inverse_of&.name
670
671
  link_back << nm
672
+ num_bt_things += 1
673
+ # puts "BT #{a.table_name}"
671
674
  "ON br_t#{idx}.id = br_t#{idx - 1}.#{a.foreign_key}"
672
675
  elsif src_ref.options[:as]
673
676
  "ON br_t#{idx}.#{src_ref.type} = '#{src_ref.active_record.name}'" + # "polymorphable_type"
@@ -686,6 +689,7 @@ module ActiveRecord
686
689
  "br_t#{idx - 1}.#{a.foreign_key} = br_t#{idx}.id"
687
690
  end
688
691
  else # Standard has_many or has_one
692
+ # puts "HM #{a.table_name}"
689
693
  # binding.pry unless (
690
694
  nm = hmt_assoc.source_reflection.inverse_of&.name
691
695
  # )
@@ -708,7 +712,13 @@ module ActiveRecord
708
712
  # binding.pry if link_back.length > 2
709
713
  "br_t#{idx}.#{hm.foreign_key}"
710
714
  else # A HMT that goes HM -> HM, something like Categories -> Products -> LineItems
711
- # binding.pry if link_back.length > 2
715
+ # %%% Currently flaky, so will revisit this soon, probably while implementing the whole link_back architecture
716
+ if num_bt_things > 1
717
+ # binding.pry
718
+ nix << k
719
+ next
720
+ end
721
+
712
722
  "br_t#{idx}.#{src_ref.active_record.primary_key}"
713
723
  end
714
724
  else
@@ -1859,18 +1869,27 @@ class Object
1859
1869
  instance_variable_set("@#{singular_table_name}".to_sym, (obj = find_obj))
1860
1870
  upd_params = send(params_name_sym)
1861
1871
  json_overrides = ::Brick.config.json_columns&.fetch(table_name, nil)
1862
- if (json_cols = model.columns.select { |c| c.type == :json || json_overrides&.include?(c.name) }.map(&:name)).present?
1872
+ if model.respond_to?(:devise_modules)
1863
1873
  upd_hash = upd_params.to_h
1874
+ upd_hash['reset_password_token'] = nil if upd_hash['reset_password_token'].blank?
1875
+ upd_hash['reset_password_sent_at'] = nil if upd_hash['reset_password_sent_at'].blank?
1876
+ if model.devise_modules.include?(:invitable)
1877
+ upd_hash['invitation_token'] = nil if upd_hash['invitation_token'].blank?
1878
+ upd_hash['invitation_created_at'] = nil if upd_hash['invitation_created_at'].blank?
1879
+ upd_hash['invitation_sent_at'] = nil if upd_hash['invitation_sent_at'].blank?
1880
+ upd_hash['invitation_accepted_at'] = nil if upd_hash['invitation_accepted_at'].blank?
1881
+ end
1882
+ end
1883
+ if (json_cols = model.columns.select { |c| c.type == :json || json_overrides&.include?(c.name) }.map(&:name)).present?
1884
+ upd_hash ||= upd_params.to_h
1864
1885
  json_cols.each do |c|
1865
1886
  begin
1866
1887
  upd_hash[c] = JSON.parse(upd_hash[c].tr('`', '"').gsub('^^br_btick__', '`'))
1867
1888
  rescue
1868
1889
  end
1869
1890
  end
1870
- obj.send(:update, upd_hash)
1871
- else
1872
- obj.send(:update, upd_params)
1873
1891
  end
1892
+ obj.send(:update, upd_hash || upd_params)
1874
1893
  end
1875
1894
 
1876
1895
  code << " def destroy\n"
@@ -1906,10 +1925,11 @@ class Object
1906
1925
  end
1907
1926
  end
1908
1927
  # Support friendly_id gem
1928
+ id_simplified = id.is_a?(Array) && id.length == 1 ? id.first : id
1909
1929
  if Object.const_defined?('FriendlyId') && model.instance_variable_get(:@friendly_id_config)
1910
- model.friendly.find(id.is_a?(Array) && id.length == 1 ? id.first : id)
1930
+ model.friendly.find(id_simplified)
1911
1931
  else
1912
- model.find(id.is_a?(Array) && id.length == 1 ? id.first : id)
1932
+ model.find(id_simplified)
1913
1933
  end
1914
1934
  end
1915
1935
  end
@@ -2044,8 +2064,18 @@ end.class_exec do
2044
2064
  load inflections
2045
2065
  end
2046
2066
  # Now the Brick initializer since there may be important schema things configured
2047
- if File.exist?(brick_initializer = ::Rails.root.join('config/initializers/brick.rb'))
2067
+ if !::Brick.initializer_loaded && File.exist?(brick_initializer = ::Rails.root.join('config/initializers/brick.rb'))
2048
2068
  ::Brick.initializer_loaded = load brick_initializer
2069
+
2070
+ # After loading the initializer, add compatibility for ActiveStorage and ActionText if those haven't already been
2071
+ # defined. (Further JSON configuration for ActiveStorage metadata happens later in the after_initialize hook.)
2072
+ ['ActiveStorage', 'ActionText'].each do |ar_extension|
2073
+ if Object.const_defined?(ar_extension) &&
2074
+ (extension = Object.const_get(ar_extension)).respond_to?(:table_name_prefix) &&
2075
+ !::Brick.config.table_name_prefixes.key?(as_tnp = extension.table_name_prefix)
2076
+ ::Brick.config.table_name_prefixes[as_tnp] = ar_extension
2077
+ end
2078
+ end
2049
2079
  end
2050
2080
  # Load the initializer for the Apartment gem a little early so that if .excluded_models and
2051
2081
  # .default_schema are specified then we can work with non-tenanted models more appropriately
@@ -2478,9 +2508,9 @@ module Brick
2478
2508
  # rubocop:enable Style/CommentedKeyword
2479
2509
 
2480
2510
  class << self
2481
- def _add_bt_and_hm(fk, relations, is_polymorphic = false, is_optional = false)
2511
+ def _add_bt_and_hm(fk, relations, polymorphic_class = nil, is_optional = false)
2482
2512
  bt_assoc_name = ::Brick.namify(fk[2], :downcase)
2483
- unless is_polymorphic
2513
+ unless polymorphic_class
2484
2514
  bt_assoc_name = if bt_assoc_name.underscore.end_with?('_id')
2485
2515
  bt_assoc_name[-3] == '_' ? bt_assoc_name[0..-4] : bt_assoc_name[0..-3]
2486
2516
  elsif bt_assoc_name.downcase.end_with?('id') && bt_assoc_name.exclude?('_')
@@ -2535,7 +2565,7 @@ module Brick
2535
2565
  puts "Brick: Additional reference #{fk.inspect} refers to non-existent #{'table'.pluralize(missing.length)} #{missing.join(' and ')}. (Available tables include #{tables.join(', ')}.)"
2536
2566
  return
2537
2567
  end
2538
- unless (cols = relations[fk[1]][:cols]).key?(fk[2]) || (is_polymorphic && cols.key?("#{fk[2]}_id") && cols.key?("#{fk[2]}_type"))
2568
+ unless (cols = relations[fk[1]][:cols]).key?(fk[2]) || (polymorphic_class && cols.key?("#{fk[2]}_id") && cols.key?("#{fk[2]}_type"))
2539
2569
  columns = cols.map { |k, v| "#{k} (#{v.first.split(' ').first})" }
2540
2570
  puts "Brick: Additional reference #{fk.inspect} refers to non-existent column #{fk[2]}. (Columns present in #{fk[1]} are #{columns.join(', ')}.)"
2541
2571
  return
@@ -2552,9 +2582,10 @@ module Brick
2552
2582
  return unless bts # Rails 5.0 and older can have bts end up being nil
2553
2583
 
2554
2584
  if (assoc_bt = bts[cnstr_name])
2555
- if is_polymorphic
2585
+ if polymorphic_class
2556
2586
  # Assuming same fk (don't yet support composite keys for polymorphics)
2557
2587
  assoc_bt[:inverse_table] << fk[4]
2588
+ assoc_bt[:polymorphic] << polymorphic_class
2558
2589
  else # Expect we could have a composite key going
2559
2590
  if assoc_bt[:fk].is_a?(String)
2560
2591
  assoc_bt[:fk] = [assoc_bt[:fk], fk[2]] unless fk[2] == assoc_bt[:fk]
@@ -2564,10 +2595,10 @@ module Brick
2564
2595
  assoc_bt[:assoc_name] = "#{assoc_bt[:assoc_name]}_#{fk[2]}"
2565
2596
  end
2566
2597
  else
2567
- inverse_table = [primary_table] if is_polymorphic
2598
+ inverse_table = [primary_table] if polymorphic_class
2568
2599
  assoc_bt = bts[cnstr_name] = { is_bt: true, fk: fk[2], assoc_name: bt_assoc_name, inverse_table: inverse_table || primary_table }
2569
2600
  assoc_bt[:optional] = true if is_optional
2570
- assoc_bt[:polymorphic] = true if is_polymorphic
2601
+ assoc_bt[:polymorphic] = [polymorphic_class] if polymorphic_class
2571
2602
  end
2572
2603
  if is_class
2573
2604
  # For use in finding the proper :source for a HMT association that references an STI subclass
@@ -2593,7 +2624,7 @@ module Brick
2593
2624
  end
2594
2625
  assoc_hm = hms[hm_cnstr_name] = { is_bt: false, fk: fk[2], assoc_name: fk_namified.pluralize, alternate_name: bt_assoc_name,
2595
2626
  inverse_table: inv_tbl, inverse: assoc_bt }
2596
- assoc_hm[:polymorphic] = true if is_polymorphic
2627
+ assoc_hm[:polymorphic] = true if polymorphic_class
2597
2628
  hm_counts = relation.fetch(:hm_counts) { relation[:hm_counts] = {} }
2598
2629
  this_hm_count = hm_counts[fk[1]] = hm_counts.fetch(fk[1]) { 0 } + 1
2599
2630
  end
@@ -188,6 +188,17 @@ function linkSchemas() {
188
188
  (app.config.assets.paths ||= []) << assets_path
189
189
  end
190
190
 
191
+ # Treat ActiveStorage::Blob metadata as JSON
192
+ if ::Brick.config.table_name_prefixes.fetch('active_storage_', nil) == 'ActiveStorage' &&
193
+ ActiveStorage.const_defined?('Blob')
194
+ unless (md = (::Brick.config.model_descrips ||= {})).key?('ActiveStorage::Blob')
195
+ md['ActiveStorage::Blob'] = '[filename]'
196
+ end
197
+ unless (asbm = (::Brick.config.json_columns['active_storage_blobs'] ||= [])).include?('metadata')
198
+ asbm << 'metadata'
199
+ end
200
+ end
201
+
191
202
  # Smarten up Avo so it recognises Brick's querystring option for Apartment multi-tenancy
192
203
  if Object.const_defined?('Avo') && ::Avo.respond_to?(:railtie_namespace)
193
204
  module ::Avo
@@ -586,7 +597,11 @@ window.addEventListener(\"popstate\", linkSchemas);
586
597
  return possible_template
587
598
  end
588
599
  rescue StandardError => e
589
- find_template_err = e # Can come up with stuff like Devise which has its own view templates
600
+ # Search through the routes to confirm that something might match (Devise stuff for instance, which has its own view templates),
601
+ # and bubble the same exception (probably an ActionView::MissingTemplate) if a legitimate option is found.
602
+ raise if ::Rails.application.routes.set.find { |x| args[1].include?(x.defaults[:controller]) && args[0] == x.defaults[:action] }
603
+
604
+ find_template_err = e
590
605
  end
591
606
  # Used to also have: ActionView.version < ::Gem::Version.new('5.0') &&
592
607
  model_name = set_brick_model(args, @_brick_req_params)&.name
@@ -646,7 +661,7 @@ window.addEventListener(\"popstate\", linkSchemas);
646
661
  (hm_fk_name.is_a?(String) && hm_fk_name.include?('.')) # HMT? (Could do a better check for this)
647
662
  predicates = path_keys(hm_assoc, hm_fk_name, pk).map do |k, v|
648
663
  if v == '[sti_type]'
649
- "'#{k}': @#{obj_name}.#{hm_assoc.active_record.inheritance_column}"
664
+ "'#{k}': (@#{obj_name}.#{hm_assoc.active_record.inheritance_column}).constantize.base_class.name"
650
665
  else
651
666
  v.is_a?(String) ? "'#{k}': '#{v}'" : "'#{k}': @#{obj_name}.#{v}"
652
667
  end
@@ -1551,8 +1566,12 @@ end
1551
1566
  <head>
1552
1567
  #{css}
1553
1568
  <title><%=
1554
- model = (obj = @#{obj_name})&.class
1555
- model_name = @#{obj_name}.#{inh_col = @_brick_model.inheritance_column} if obj.respond_to?(:#{inh_col})
1569
+ base_model = (model = (obj = @#{obj_name})&.class).base_class
1570
+ see_all_path = send(\"#\{base_model._brick_index}_path\")
1571
+ if obj.respond_to?(:#{inh_col = @_brick_model.inheritance_column}) &&
1572
+ (model_name = @#{obj_name}.#{inh_col}) != base_model.name
1573
+ see_all_path << \"?#{inh_col}=#\{model_name}\"
1574
+ end
1556
1575
  page_title = (\"#\{model_name ||= model.name}: #\{obj&.brick_descrip || controller_name}\")
1557
1576
  %></title>
1558
1577
  </head>
@@ -1596,7 +1615,7 @@ end
1596
1615
  if (description = (relation = Brick.relations[tbl_name = #{model_name}.table_name])&.fetch(:description, nil)) %><%=
1597
1616
  description %><br><%
1598
1617
  end
1599
- %><%= link_to '(See all #{obj_name.pluralize})', #{@_brick_model._brick_index}_path %>
1618
+ %><%= link_to \"(See all #\{model_name.pluralize})\", see_all_path %>
1600
1619
  #{erd_markup}
1601
1620
  <% if obj
1602
1621
  # path_options = [obj.#{pk}]
@@ -1612,11 +1631,11 @@ end
1612
1631
  <%= form_for(obj.becomes(#{model_name}), options) do |f| %>
1613
1632
  <table class=\"shadow\">
1614
1633
  <% has_fields = false
1615
- @#{obj_name}.attributes.each do |k, val|
1616
- col = #{model_name}.columns_hash[k] %>
1617
- <tr>
1618
- <% next if (#{(pk || []).inspect}.include?(k) && !bts.key?(k)) ||
1634
+ @#{obj_name}.attributes.each do |k, val|
1635
+ next if !(col = #{model_name}.columns_hash[k]) ||
1636
+ (#{(pk || []).inspect}.include?(k) && !bts.key?(k)) ||
1619
1637
  ::Brick.config.metadata_columns.include?(k) %>
1638
+ <tr>
1620
1639
  <th class=\"show-field\"<%= \" title=\\\"#\{col.comment}\\\"\".html_safe if col.respond_to?(:comment) && !col.comment.blank? %>>
1621
1640
  <% has_fields = true
1622
1641
  if (bt = bts[k])
@@ -1680,9 +1699,13 @@ end
1680
1699
  if is_bcrypt?(val) # || .readonly?
1681
1700
  is_revert = false %>
1682
1701
  <%= hide_bcrypt(val, nil, 1000) %>
1683
- <% elsif col_type == :string %>
1684
- <%= f.text_field(k.to_sym, html_options) %>
1685
- <% else
1702
+ <% elsif col_type == :string
1703
+ if model.respond_to?(:enumerized_attributes) && (opts = model.enumerized_attributes[k]&.options).present? %>
1704
+ <%= f.select(k.to_sym, [[\"(No #\{k} chosen)\", '^^^brick_NULL^^^']] + opts, { value: val || '^^^brick_NULL^^^' }, html_options) %><%
1705
+ else %>
1706
+ <%= f.text_field(k.to_sym, html_options) %><%
1707
+ end
1708
+ else
1686
1709
  is_includes_text = true %>
1687
1710
  <%= f.hidden_field(k.to_sym, html_options) %>
1688
1711
  <trix-editor input=\"<%= f.field_id(k) %>\"></trix-editor>
@@ -170,11 +170,8 @@ module Brick::Rails::FormTags
170
170
  if klass
171
171
  type_col = klass.inheritance_column # Usually 'type'
172
172
  filter_parts << "#{type_col}=#{sti_type}" if sti_type && klass.column_names.include?(type_col)
173
- path_params = request.path_parameters.dup
174
- path_params.delete(:controller)
175
- path_params.delete(:action)
173
+ path_params = request.path_parameters
176
174
  pk = (klass.primary_key || ActiveRecord::Base.primary_key).to_sym
177
- # Used to also have this but it's a bit too permissive to identify a primary key: (path_params.length == 1 && path_params.values.first) ||
178
175
  if ((id = (path_params[pk] || path_params[:id] || path_params["#{klass.name.underscore}_id".to_sym])) && (obj = klass.find_by(pk => id))) ||
179
176
  (['show', 'edit', 'update', 'destroy'].include?(action_name) && (obj = klass.first))
180
177
  obj
@@ -183,7 +180,18 @@ module Brick::Rails::FormTags
183
180
  # %%% If there is a polymorphic association that might relate to stuff in the path_params,
184
181
  # try to identify an appropriate ___able_id and ___able_type filter
185
182
  ((klass.column_names - [pk.to_s]) & path_params.keys.map(&:to_s)).each do |path_param|
186
- filter_parts << "#{path_param}=#{path_params[path_param.to_sym]}"
183
+ next if [:controller, :action].include?(path_param)
184
+
185
+ foreign_id = path_params[path_param.to_sym]
186
+ # Need to convert a friendly_id slug to a real ID?
187
+ if Object.const_defined?('FriendlyId') &&
188
+ (assoc = klass.reflect_on_all_associations.find { |a| a.belongs_to? && a.foreign_key == path_param }) &&
189
+ (assoc_klass = assoc.klass).instance_variable_get(:@friendly_id_config) &&
190
+ (new_id = assoc_klass.where(assoc_klass.friendly_id_config.query_field => foreign_id)
191
+ .pluck(assoc_klass.primary_key).first)
192
+ foreign_id = new_id
193
+ end
194
+ filter_parts << "#{path_param}=#{foreign_id}"
187
195
  end
188
196
  klass
189
197
  end
@@ -5,7 +5,7 @@ module Brick
5
5
  module VERSION
6
6
  MAJOR = 1
7
7
  MINOR = 0
8
- TINY = 122
8
+ TINY = 124
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
@@ -208,7 +208,7 @@ module Brick
208
208
  if a.polymorphic?
209
209
  rel_poly_bt = relations[model.table_name][:fks].find { |_k, fk| fk[:assoc_name] == a.name.to_s }
210
210
  if (primary_tables = rel_poly_bt&.last&.fetch(:inverse_table, [])).is_a?(Array)
211
- models = primary_tables&.map { |table| table.singularize.camelize.constantize }
211
+ models = rel_poly_bt[1][:polymorphic]&.map { |table| table.singularize.camelize.constantize }
212
212
  s.first[a.foreign_key.to_s] = [a.name, models, true]
213
213
  else
214
214
  # This will come up when using Devise invitable when invited_by_class_name is not
@@ -523,8 +523,13 @@ module Brick
523
523
  table_name, poly = k.split('.')
524
524
  v ||= ActiveRecord::Base.execute_sql("SELECT DISTINCT #{poly}_type AS typ FROM #{table_name}").each_with_object([]) { |result, s| s << result['typ'] if result['typ'] }
525
525
  v.each do |type|
526
- if relations.key?(primary_table = type.underscore.pluralize)
527
- ::Brick._add_bt_and_hm([nil, table_name, poly, nil, primary_table, "(brick) #{table_name}_#{poly}"], relations, true, is_optional)
526
+ # Allow polymorphic BT to relate to an STI subclass
527
+ base_type = ::Brick.config.sti_namespace_prefixes["::#{type}"] ||
528
+ ::Brick.config.sti_namespace_prefixes.find { |k, _v| type.start_with?(k[2..-1]) }&.last&.[](2..-1)
529
+ if relations.key?(primary_table = (base_type || type).underscore.pluralize)
530
+ ::Brick._add_bt_and_hm([nil, table_name, poly, nil, primary_table, "(brick) #{table_name}_#{poly}"], relations,
531
+ type, # Polymorphic class
532
+ is_optional)
528
533
  else
529
534
  missing_stis[primary_table] = type unless ::Brick.existing_stis.key?(type)
530
535
  end
@@ -1694,6 +1699,29 @@ if Gem::Specification.all_names.any? { |g| g.start_with?('ransack-') }
1694
1699
  end
1695
1700
  end
1696
1701
 
1702
+ # Patch Enumerize so that #becomes works when an STI subclass is becoming a base class
1703
+ # which does not include Enumerize.
1704
+ # (See https://github.com/brainspec/enumerize/issues/426)
1705
+ if Object.const_defined?('Enumerize') && Enumerize.const_defined?('ActiveRecordSupport')
1706
+ Enumerize::ActiveRecordSupport::InstanceMethods.class_exec do
1707
+ def becomes(klass)
1708
+ became = super
1709
+ klass = self.class unless klass.respond_to?(:enumerized_attributes)
1710
+ klass.enumerized_attributes.each do |attr|
1711
+ begin
1712
+ if became.respond_to?(setter = "#{attr.name}=")
1713
+ became.send(setter, send(attr.name))
1714
+ end
1715
+ rescue ActiveModel::MissingAttributeError
1716
+ rescue ActiveRecord::SerializationTypeMismatch
1717
+ became.send(setter, send(attr.name).to_ary)
1718
+ end
1719
+ end
1720
+ became
1721
+ end
1722
+ end
1723
+ end
1724
+
1697
1725
  # Keyword arguments updates for Rails <= 5.2.x and Ruby >= 3.0
1698
1726
  if ActiveRecord.version < ::Gem::Version.new('6.0') && ruby_version >= ::Gem::Version.new('3.0')
1699
1727
  admsm = ActionDispatch::MiddlewareStack::Middleware
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.122
4
+ version: 1.0.124
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-03-23 00:00:00.000000000 Z
11
+ date: 2023-03-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord