brick 1.0.150 → 1.0.152

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: 7914cc56d8cd8919835028d5ad9b05a50a2b17baf32c9699d1f78bbaf9417e0d
4
- data.tar.gz: a7f945e136fe8401c54e8fd24a4d92a5cef24b22bb68d2caceac28d809ff8f07
3
+ metadata.gz: 4b4101e6f3437aaf0cb79eec97a94b9df6655d9db8a4773e761768556d2ec31f
4
+ data.tar.gz: 543bad78f1a359af9126373928789d868530b7ed09c17dbf18bf52a012a37763
5
5
  SHA512:
6
- metadata.gz: fa3ed344e3d4beed83cf9a6fd7059d78032497f8a6c51c825fd50d163e61bd8029afe3dd82e055631d8258b0c9cf54f7d176e064c47fe9fb5a70cc25cdb67faf
7
- data.tar.gz: e43ca92a155c805d4dc5be0a2548d9612bc0b1a92cb2e65722ca4c55c81dbef9b476493d6764eece75489e9caf60e2a1046ca960d9a58cafe060aeae11db954a
6
+ metadata.gz: 84d77e9a74428eea4e90f0a40b6e2a6dc824623a6b8975659698b4c79b73ec2ec5f5f26409c5d3d7f0c89c33e6c0aafb73a0c69b8cb3900654d10c528f3d4699
7
+ data.tar.gz: 556ad657abeb7a2368940a8b651ef85e6d3c410684e3ab7a088d741ea851e5c31b51bbe8f8baaa017231f56eb7fa177928782b68c6ee7b00c053d1267ac67a1f
data/lib/brick/config.rb CHANGED
@@ -204,6 +204,15 @@ module Brick
204
204
  @mutex.synchronize { @has_ones = hos }
205
205
  end
206
206
 
207
+ # Associations upon which to add #accepts_nested_attributes_for logic
208
+ def nested_attributes
209
+ @mutex.synchronize { @nested_attributes }
210
+ end
211
+
212
+ def nested_attributes=(anaf)
213
+ @mutex.synchronize { @nested_attributes = anaf }
214
+ end
215
+
207
216
  # Polymorphic associations
208
217
  def polymorphics
209
218
  @mutex.synchronize { @polymorphics }
@@ -344,6 +344,28 @@ module ActiveRecord
344
344
  def _br_cust_cols
345
345
  @_br_cust_cols ||= {}
346
346
  end
347
+
348
+ def _brick_find_permits(model_or_assoc, current_permits, done_permits = [])
349
+ unless done_permits.include?(model_or_assoc)
350
+ done_permits << model_or_assoc
351
+ self.reflect_on_all_associations.select { |assoc| !assoc.belongs_to? }.each_with_object([]) do |assoc, s|
352
+ if assoc.options[:through]
353
+ current_permits << { "#{assoc.name.to_s.singularize}_ids".to_sym => [] }
354
+ s << "#{assoc.name.to_s.singularize}_ids: []"
355
+ end
356
+ if self.instance_methods.include?(:"#{assoc.name}_attributes=")
357
+ # Support nested attributes which use the friendly_id gem
358
+ assoc.klass._brick_nested_friendly_id if Object.const_defined?('FriendlyId') &&
359
+ assoc.klass.instance_variable_get(:@friendly_id_config)
360
+ new_attrib_text = assoc.klass._brick_find_permits(assoc, (new_permits = assoc.klass.columns_hash.keys.map(&:to_sym)), done_permits)
361
+ new_permits << :_destroy
362
+ current_permits << { "#{assoc.name}_attributes".to_sym => new_permits }
363
+ s << "#{assoc.name}_attributes: #{new_attrib_text}"
364
+ end
365
+ end
366
+ end
367
+ current_permits
368
+ end
347
369
  end
348
370
 
349
371
  # Search for custom column, BT, HM, and HMT DSL stuff
@@ -1528,12 +1550,12 @@ class Object
1528
1550
  # end
1529
1551
  end
1530
1552
 
1531
- # Enable Turbo Stream if possible -- equivalent of: broadcasts_to ->(comment) { :comments }
1532
- if Object.const_defined?(:ApplicationCable) && Object.const_defined?(:Turbo) && Turbo.const_defined?(:Broadcastable) && respond_to?(:broadcasts_to)
1533
- relation[:broadcasts] = true
1534
- self.broadcasts_to ->(model) { (model&.class&.name || chosen_name).underscore.pluralize.to_sym }
1535
- code << " broadcasts_to ->(#{chosen_name}) { #{chosen_name}&.class&.name&.underscore&.pluralize&.to_sym }\n"
1536
- end
1553
+ # # %%% Enable Turbo Stream if possible -- equivalent of: broadcasts_to ->(comment) { :comments }
1554
+ # if Object.const_defined?(:ApplicationCable) && Object.const_defined?(:Turbo) && Turbo.const_defined?(:Broadcastable) && respond_to?(:broadcasts_to)
1555
+ # relation[:broadcasts] = true
1556
+ # self.broadcasts_to ->(model) { (model&.class&.name || chosen_name).underscore.pluralize.to_sym }
1557
+ # code << " broadcasts_to ->(#{chosen_name}) { #{chosen_name}&.class&.name&.underscore&.pluralize&.to_sym }\n"
1558
+ # end
1537
1559
  end # class definition
1538
1560
  # Having this separate -- will this now work out better?
1539
1561
  built_model.class_exec do
@@ -1639,18 +1661,23 @@ class Object
1639
1661
  else
1640
1662
  need_fk = "#{ActiveSupport::Inflector.singularize(assoc[:inverse][:inverse_table].split('.').last)}_id" != assoc[:fk]
1641
1663
  end
1664
+ singular_assoc_name = ActiveSupport::Inflector.singularize(assoc_name.tr('.', '_'))
1642
1665
  has_ones = ::Brick.config.has_ones&.fetch(full_name, nil)
1643
- if has_ones&.key?(singular_assoc_name = ActiveSupport::Inflector.singularize(assoc_name.tr('.', '_')))
1644
- assoc_name = if (custom_assoc_name = has_ones[singular_assoc_name])
1645
- need_class_name = custom_assoc_name != singular_assoc_name
1646
- custom_assoc_name
1647
- else
1648
- singular_assoc_name
1649
- end
1650
- :has_one
1651
- else
1652
- :has_many
1653
- end
1666
+ macro = if has_ones&.key?(singular_assoc_name)
1667
+ assoc_name = if (custom_assoc_name = has_ones[singular_assoc_name])
1668
+ need_class_name = custom_assoc_name != singular_assoc_name
1669
+ custom_assoc_name
1670
+ else
1671
+ singular_assoc_name
1672
+ end
1673
+ :has_one
1674
+ else
1675
+ :has_many
1676
+ end
1677
+ # Auto-create an accepts_nested_attributes_for for this HM?
1678
+ is_anaf = (anaf = ::Brick.config.nested_attributes&.fetch(full_name, nil)) &&
1679
+ (anaf.is_a?(Array) ? anaf.include?(assoc_name) : anaf == assoc_name)
1680
+ macro
1654
1681
  end
1655
1682
  # Figure out if we need to specially call out the class_name and/or foreign key
1656
1683
  # (and if either of those then definitely also a specific inverse_of)
@@ -1686,6 +1713,10 @@ class Object
1686
1713
  assoc_name = assoc_name.tr('.', '_').to_sym
1687
1714
  code << " #{macro} #{assoc_name.inspect}#{options.map { |k, v| ", #{k}: #{v.inspect}" }.join}\n"
1688
1715
  self.send(macro, assoc_name, **options)
1716
+ if is_anaf
1717
+ code << " accepts_nested_attributes_for #{assoc_name.inspect}\n"
1718
+ self.send(:accepts_nested_attributes_for, assoc_name)
1719
+ end
1689
1720
  end
1690
1721
 
1691
1722
  def default_ordering(table_name, pk)
@@ -2155,13 +2186,16 @@ class Object
2155
2186
  ::Brick.set_db_schema(params)
2156
2187
  if request.format == :csv # Importing CSV?
2157
2188
  require 'csv'
2189
+
2158
2190
  # See if internally it's likely a TSV file (tab-separated)
2159
- tab_counts = []
2160
- 5.times { tab_counts << request.body.readline.count("\t") unless request.body.eof? }
2191
+ likely_separator = Hash.new { |h, k| h[k] = 0 }
2192
+ request.body.readline # Expect first row to have column headers
2193
+ 5.times { ::Brick._find_csv_separator(request.body, likely_separator) unless request.body.eof? }
2161
2194
  request.body.rewind
2162
- separator = "\t" if tab_counts.length > 0 && tab_counts.uniq.length == 1 && tab_counts.first > 0
2163
- result = model.df_import(CSV.parse(request.body, { col_sep: separator || :auto }), model.brick_import_template)
2164
- # render inline: exported_csv, content_type: request.format
2195
+ separator = "\t" if likely_separator["\t"] > likely_separator[',']
2196
+
2197
+ result = model.df_import(CSV.parse(request.body, **{ col_sep: separator || :auto }), model.brick_import_template)
2198
+ render inline: result.to_json, content_type: request.format
2165
2199
  return
2166
2200
  # elsif request.format == :js # Asking for JSON?
2167
2201
  # render inline: model.df_export(true).to_json, content_type: request.format
@@ -2191,6 +2225,9 @@ class Object
2191
2225
  end
2192
2226
  end
2193
2227
  end
2228
+ if (upd_hash ||= upd_params).fetch(model.inheritance_column, nil).strip == ''
2229
+ upd_hash[model.inheritance_column] = nil
2230
+ end
2194
2231
  obj.send(:update, upd_hash || upd_params)
2195
2232
  end
2196
2233
 
@@ -2238,9 +2275,9 @@ class Object
2238
2275
 
2239
2276
  if is_need_params
2240
2277
  code << " def #{params_name}\n"
2241
- permits_txt = self._brick_find_permits(model, (permits = model.columns_hash.keys.map(&:to_sym)))
2278
+ permits_txt = model._brick_find_permits(model, permits = model.columns_hash.keys.map(&:to_sym))
2242
2279
  code << " params.require(:#{require_name = model.name.underscore.tr('/', '_')
2243
- }).permit(#{permits_txt.join(', ')})\n"
2280
+ }).permit(#{permits_txt.map(&:inspect).join(', ')})\n"
2244
2281
  code << " end\n"
2245
2282
  self.define_method(params_name) do
2246
2283
  params.require(require_name.to_sym).permit(permits)
@@ -2254,24 +2291,6 @@ class Object
2254
2291
  [built_controller, code]
2255
2292
  end
2256
2293
 
2257
- def _brick_find_permits(model, current_permits)
2258
- model.reflect_on_all_associations.select { |assoc| assoc.macro == :has_many }.each_with_object([]) do |assoc, s|
2259
- if assoc.options[:through]
2260
- current_permits << { "#{assoc.name.to_s.singularize}_ids".to_sym => [] }
2261
- s << "#{assoc.name.to_s.singularize}_ids: []"
2262
- elsif assoc.active_record.instance_methods.include?(:"#{assoc.name}_attributes=")
2263
- # Support nested attributes which use the friendly_id gem
2264
- self._brick_nested_friendly_id if Object.const_defined?('FriendlyId') &&
2265
- assoc.klass.instance_variable_get(:@friendly_id_config)
2266
- new_attrib_text = self._brick_find_permits(assoc.klass, (new_permits = assoc.klass.columns_hash.keys.map(&:to_sym)))
2267
- new_permits << :_destroy
2268
- current_permits << { "#{assoc.name}_attributes".to_sym => new_permits }
2269
- s << "#{assoc.name}_attributes: #{new_attrib_text}"
2270
- end
2271
- end
2272
- current_permits
2273
- end
2274
-
2275
2294
  def _brick_nested_friendly_id
2276
2295
  unless @_brick_nested_friendly_id
2277
2296
  ::ActiveRecord::Base.class_exec do
@@ -257,17 +257,20 @@ function linkSchemas() {
257
257
  # Has one relationships
258
258
  ::Brick.has_ones = app.config.brick.fetch(:has_ones, nil)
259
259
 
260
+ # accepts_nested_attributes_for relationships
261
+ ::Brick.nested_attributes = app.config.brick.fetch(:nested_attributes, nil)
262
+
260
263
  # Polymorphic associations
261
264
  ::Brick.polymorphics = app.config.brick.fetch(:polymorphics, nil)
262
265
  end
263
266
 
264
267
  # After we're initialized and before running the rest of stuff, put our configuration in place
265
268
  ActiveSupport.on_load(:after_initialize) do |app|
266
- assets_path = File.expand_path("#{__dir__}/../../../../vendor/assets")
267
- if (app_config = app.config).respond_to?(:assets)
268
- (app_config.assets.precompile ||= []) << "#{assets_path}/images/brick_erd.png"
269
- (app.config.assets.paths ||= []) << assets_path
270
- end
269
+ # assets_path = File.expand_path("#{__dir__}/../../../../vendor/assets")
270
+ # if (app_config = app.config).respond_to?(:assets)
271
+ # (app_config.assets.precompile ||= []) << "#{assets_path}/images/brick_erd.png"
272
+ # (app.config.assets.paths ||= []) << assets_path
273
+ # end
271
274
 
272
275
  # Treat ActiveStorage::Blob metadata as JSON
273
276
  if ::Brick.config.table_name_prefixes.fetch('active_storage_', nil) == 'ActiveStorage' &&
@@ -813,7 +816,7 @@ h1, h3 {
813
816
  margin-bottom: 0;
814
817
  }
815
818
  #imgErd {
816
- background-image:url(/assets/brick_erd.png);
819
+ background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAE0AAABNCAMAAADU1xmCAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAARxaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJYTVAgQ29yZSA2LjAuMCI+CiAgIDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+CiAgICAgIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICAgICAgICAgIHhtbG5zOnRpZmY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vdGlmZi8xLjAvIgogICAgICAgICAgICB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIKICAgICAgICAgICAgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiCiAgICAgICAgICAgIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyI+CiAgICAgICAgIDx0aWZmOllSZXNvbHV0aW9uPjcyPC90aWZmOllSZXNvbHV0aW9uPgogICAgICAgICA8dGlmZjpYUmVzb2x1dGlvbj43MjwvdGlmZjpYUmVzb2x1dGlvbj4KICAgICAgICAgPHRpZmY6T3JpZW50YXRpb24+MTwvdGlmZjpPcmllbnRhdGlvbj4KICAgICAgICAgPHhtcE1NOkRlcml2ZWRGcm9tIHJkZjpwYXJzZVR5cGU9IlJlc291cmNlIj4KICAgICAgICAgICAgPHN0UmVmOmluc3RhbmNlSUQ+eG1wLmlpZDoxN0U3OEI3RjAzN0MxMUU3QTZDMDhBQjVCRDc2QkZCQjwvc3RSZWY6aW5zdGFuY2VJRD4KICAgICAgICAgICAgPHN0UmVmOmRvY3VtZW50SUQ+eG1wLmRpZDoxN0U3OEI4MDAzN0MxMUU3QTZDMDhBQjVCRDc2QkZCQjwvc3RSZWY6ZG9jdW1lbnRJRD4KICAgICAgICAgPC94bXBNTTpEZXJpdmVkRnJvbT4KICAgICAgICAgPHhtcE1NOkRvY3VtZW50SUQ+eG1wLmRpZDoxN0U3OEI4MjAzN0MxMUU3QTZDMDhBQjVCRDc2QkZCQjwveG1wTU06RG9jdW1lbnRJRD4KICAgICAgICAgPHhtcE1NOkluc3RhbmNlSUQ+eG1wLmlpZDoxN0U3OEI4MTAzN0MxMUU3QTZDMDhBQjVCRDc2QkZCQjwveG1wTU06SW5zdGFuY2VJRD4KICAgICAgICAgPHhtcDpDcmVhdG9yVG9vbD5BZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3M8L3htcDpDcmVhdG9yVG9vbD4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+ChMBcXgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAL9UExURUdwTDRRc1EVG6ioqFJSUmJiYn+AgURWa2uEkauorszGwmtrawonUKzY7DMRIlFTVWV9m4qKiwaN0G1raJSQiJjV7jWh2HmizPLs6CaV0QohSmdoaVdXWLWsomFdYmIgD4WCfQWa2WIoFUxylldpekeRuGtrajhztIuLizV3qc3DvThDVEyFs31+fiRViVRNViVWjwsvWxIzXxZEekeL1FZIVVRdeEZrk359fj52ppubm3l6e4qbqJOTlBlGfM3k3Nzc3K6lnk9RWaenp0FjikGDyJGRkWJiYk2L0Li4uJubnH5+flFbeNPT02tpac3NzVBGJkCCyMvLy9LS0oxETk2U3tLS0tXV1cPDw+Xl5amDftbX19na2uLj4+jo6dzd3OXl511dXd/g31paWlZXV9TU1HBwcOvr687OzdDQ0u/u7fTx79PSzcrJx6KiooWFhujn5NvW05WUk7S1t3R1d7y9vcLCv37J68vMzVJTVOLY1gMiSpmamnt7e7K6zHq+43LQ9Vyez+Pf3LGyscXGybzD1sXDw46v02vI8I+Pj7vEtNvIx7q4ubnZ54a3it3f5s+8vGS/6L6trK+6qICs1H+33cXc6KiuwAOr48fN20ee0Fao0lyz4W6s1qyrrKKlt3XdkoqnyyFoqzuTy6ixosuVeobA4YHNl8TOv3/Ck9bc4I3P7Uqq3tDIxz2FwzN/vF+VxdDe59mIfU+OxJmovxl+wX7S9WjbhovW9jihyKGalIq31uNyY36exJCatJONhTm36nKj0B2q4Mqxsae2zc/U3tvf1cqKa7zAyJS4npqyyTh2tUhMT1drj5ixtN98cEfC8U2Y5vf39355cSN0s4mDfKaomlrG8b2cmcFvaGx/m2CeZge68HG64YCNntSgoVHUdJzKnIHIh6c+BalVVaPM5qrG2CZZkyaHH3WRtYrdn5nH2rxoP22+gN1VQTyxW1aXl0iO2GaxtFuzaCCAQyXSWDOKlDZwkxIINVZPP52Io3uldtIoC1uGVxmzRP6PHn8AAADVdFJOUwAmEf6t/v4EAQVR/oT+Hl4U/v1bR/7+Kf7+a/76Q4Y2Wf1b4j71sXm0y2hF/bBwbtXN/fyGl8Sxiu382Preqfzia9iIkdP51/Povnineu+9n6H7ov5ksLfYy/7////////+/////////////////////v/////////////////////////////////////////////////////////////////////////////+/////////////////////////////////////////////////////r5xM8kAAA0qSURBVFjDpZh3WFNnG8YDMZOiLEFEsVhn1Vq1Vq1abWv3br+dc5IQsklCSEiIyAoJyAhb9h4ishVQcCAIOLC4UBFxr7bu0X6dX6/vec8JikIptecPVrh+576f5z3vez+HQmGyKBSK28eT4SsL/fiXLiaFwmD/E5NzPmU7wG8s5l/DOXy8+vhxLg8TcN5/yw0JZPwV2GoJH+fjPI7UHBWV/8HzwGIynlkgm+vv788RiURSs06bT6WuJAQynlEgO+JaUzoWhGAWE1X1mkqlmYUEMp5JIBs7ejYz3L4iyN+gy1epVMGvaYI1K5faIIF/nsfuPDr325LMo5XpvCCFThUMrHccY2L85j2TQHZna11kZFGd19lo+4oI/yiqJiYmxtGP7kdf/gwC2bLWuix1RWTX7uzMo+PTI4KkJo0fXPSQkBDxDOc/KZBtaK3P4uLqrPXri+rcz4YjgbpgegidHhIgDhC/6/mnBLLNVTWdclzdmbYTeAMClVS6OCAgQGxnZ0cbM4dBPDKjoh2oqo309ZV3ppWV7UTAur1nw+MrIhRaRzsPsdiDRqN5v+lpO0oc0OrrirLkiWGVZVYeIXBLRFBUsNiH5kHz9vHxeZMxOhxb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);
817
820
  background-size: 100% 100%;
818
821
  width: 2.2em;
819
822
  height: 2.2em;
@@ -1241,7 +1244,9 @@ erDiagram
1241
1244
  btnImport.style.display = droppedTSV.length > 0 ? \"block\" : \"none\";
1242
1245
  });
1243
1246
  btnImport.addEventListener(\"click\", function () {
1244
- fetch(changeout(<%= #{path_obj_name}_path(-1, format: :csv).inspect.html_safe %>, \"_brick_schema\", brickSchema), {
1247
+ var patchPath = <%= #{path_obj_name}_path(-1, format: :csv).inspect.html_safe %>;
1248
+ if (brickSchema) patchPath = changeout(patchPath, \"_brick_schema\", brickSchema);
1249
+ fetch(patchPath, {
1245
1250
  method: \"PATCH\",
1246
1251
  headers: { \"Content-Type\": \"text/tab-separated-values\" },
1247
1252
  body: droppedTSV
@@ -5,7 +5,7 @@ module Brick
5
5
  module VERSION
6
6
  MAJOR = 1
7
7
  MINOR = 0
8
- TINY = 150
8
+ TINY = 152
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
@@ -477,6 +477,12 @@ module Brick
477
477
  end
478
478
  end
479
479
 
480
+ # Associations upon which to add #accepts_nested_attributes_for logic
481
+ # @api public
482
+ def nested_attributes=(anaf)
483
+ Brick.config.nested_attributes = anaf
484
+ end
485
+
480
486
  # Polymorphic associations
481
487
  def polymorphics=(polys)
482
488
  polys = polys.each_with_object({}) { |poly, s| s[poly] = nil } if polys.is_a?(Array)
@@ -742,6 +748,28 @@ In config/initializers/brick.rb appropriate entries would look something like:
742
748
  @double_underscore_applied = true
743
749
  end
744
750
  end
751
+
752
+ def _find_csv_separator(stream, likely_separator)
753
+ line = nil
754
+ last_char = nil
755
+ in_quotes = false
756
+ ret = +''
757
+ while true
758
+ (line = stream.readline).each_char do |ch|
759
+ likely_separator[ch] += 2 if !in_quotes && last_char == '"' && ch != "\n"
760
+ if ch == '"'
761
+ in_quotes = !in_quotes
762
+ likely_separator[last_char] += 2 if in_quotes && last_char != "\n"
763
+ end
764
+ last_char = ch
765
+ end
766
+ ret << line
767
+ break if !in_quotes || stream.eof?
768
+ end
769
+ likely_separator[line[0]] += 1
770
+ likely_separator[line[-2]] += 1
771
+ ret
772
+ end
745
773
  end
746
774
 
747
775
  module RouteSet
@@ -256,6 +256,10 @@ if ActiveRecord::Base.respond_to?(:brick_select) && !::Brick.initializer_loaded
256
256
  # # instead of \"user_profile\", then apply that as a third parameter like this:
257
257
  # Brick.has_ones = [['User', 'user_profile', 'profile']]
258
258
 
259
+ # # Automatically establish #accepts_nested_attributes_for logic on has_many and has_one associations.
260
+ # # This video to demonstrates how this works: https://github.com/lorint/brick/assets/5301131/82ac4f6d-bc23-4a55-adab-bc754bcb0f26
261
+ # Brick.nested_attributes = { 'User' => ['profile', 'posts'] }
262
+
259
263
  # # We normally don't show the timestamp columns \"created_at\", \"updated_at\", and \"deleted_at\", and also do
260
264
  # # not consider them when finding associative tables to support an N:M association. (That is, ones that can be a
261
265
  # # part of a has_many :through association.) If you want to use different exclusion columns than our defaults
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.150
4
+ version: 1.0.152
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-06-03 00:00:00.000000000 Z
11
+ date: 2023-06-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord