brick 1.0.21 → 1.0.24
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 +4 -4
- data/lib/brick/extensions.rb +171 -87
- data/lib/brick/frameworks/rails/engine.rb +183 -54
- data/lib/brick/version_number.rb +1 -1
- data/lib/brick.rb +2 -9
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 96ba9e8b4ddc54e5feaaf8652c93e5d9e1ffe15345a8cad719674e051b296718
|
4
|
+
data.tar.gz: 3901467e7918ece559f55740759bd555bababe96c407488307fcb01298c14034
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aa73995e69947be5ca83597a71751cfffb2433551d04fb00b760bc51c199bcd9890d7a05c0deb2f2c07c2c89205acf52b942d00ae78e1d7c0a26544acf70a4d0
|
7
|
+
data.tar.gz: 2328082844a0c993ada29c02eab22cf0d04efbcf3e4479c804e16f7d2a39a42d28debcd5592620fecd3bc9c404458fe3b5ff448f1f2c1b7f0d2e13557f5f9fa8
|
data/lib/brick/extensions.rb
CHANGED
@@ -26,18 +26,13 @@
|
|
26
26
|
|
27
27
|
# colour coded origins
|
28
28
|
|
29
|
-
# Drag something like
|
29
|
+
# Drag something like HierModel#name onto the rows and have it automatically add five columns -- where type=zone / where type = section / etc
|
30
30
|
|
31
31
|
# Support for Postgres / MySQL enums (add enum to model, use model enums to make a drop-down in the UI)
|
32
32
|
|
33
33
|
# Currently quadrupling up routes
|
34
34
|
|
35
35
|
|
36
|
-
# From the North app:
|
37
|
-
# undefined method `built_in_role_path' when referencing show on a subclassed STI:
|
38
|
-
# http://localhost:3000/roles/3?_brick_schema=cust1
|
39
|
-
|
40
|
-
|
41
36
|
# ==========================================================
|
42
37
|
# Dynamically create model or controller classes when needed
|
43
38
|
# ==========================================================
|
@@ -120,8 +115,8 @@ module ActiveRecord
|
|
120
115
|
# If available, parse simple DSL attached to a model in order to provide a friendlier name.
|
121
116
|
# Object property names can be referenced in square brackets like this:
|
122
117
|
# { 'User' => '[profile.firstname] [profile.lastname]' }
|
123
|
-
def brick_descrip
|
124
|
-
self.class.brick_descrip(self)
|
118
|
+
def brick_descrip(data = nil, pk_alias = nil)
|
119
|
+
self.class.brick_descrip(self, data, pk_alias)
|
125
120
|
end
|
126
121
|
|
127
122
|
def self.brick_descrip(obj, data = nil, pk_alias = nil)
|
@@ -141,11 +136,7 @@ module ActiveRecord
|
|
141
136
|
this_obj = obj
|
142
137
|
bracket_name.split('.').each do |part|
|
143
138
|
obj_name += ".#{part}"
|
144
|
-
this_obj =
|
145
|
-
caches[obj_name]
|
146
|
-
else
|
147
|
-
(caches[obj_name] = this_obj&.send(part.to_sym))
|
148
|
-
end
|
139
|
+
this_obj = caches.fetch(obj_name) { caches[obj_name] = this_obj&.send(part.to_sym) }
|
149
140
|
end
|
150
141
|
this_obj&.to_s || ''
|
151
142
|
end
|
@@ -165,17 +156,38 @@ module ActiveRecord
|
|
165
156
|
end
|
166
157
|
if is_brackets_have_content
|
167
158
|
output
|
168
|
-
elsif pk_alias
|
169
|
-
|
170
|
-
|
159
|
+
elsif (pk_alias ||= primary_key)
|
160
|
+
pk_alias = [pk_alias] unless pk_alias.is_a?(Array)
|
161
|
+
id = []
|
162
|
+
pk_alias.each do |pk_alias_part|
|
163
|
+
if (pk_part = obj.send(pk_alias_part))
|
164
|
+
id << pk_part
|
165
|
+
end
|
166
|
+
end
|
167
|
+
if id.present?
|
168
|
+
"#{klass.name} ##{id.join(', ')}"
|
171
169
|
end
|
172
|
-
# elsif klass.primary_key
|
173
|
-
# "#{klass.name} ##{obj.send(klass.primary_key)}"
|
174
170
|
else
|
175
171
|
obj.to_s
|
176
172
|
end
|
177
173
|
end
|
178
174
|
|
175
|
+
def self.bt_link(assoc_name)
|
176
|
+
model_underscore = name.underscore
|
177
|
+
assoc_name = CGI.escapeHTML(assoc_name.to_s)
|
178
|
+
model_path = Rails.application.routes.url_helpers.send("#{model_underscore.pluralize}_path".to_sym)
|
179
|
+
link = Class.new.extend(ActionView::Helpers::UrlHelper).link_to(name, model_path)
|
180
|
+
model_underscore == assoc_name ? link : "#{assoc_name}-#{link}".html_safe
|
181
|
+
end
|
182
|
+
|
183
|
+
def self.brick_import_template
|
184
|
+
template = constants.include?(:IMPORT_TEMPLATE) ? self::IMPORT_TEMPLATE : suggest_template(false, false, 0)
|
185
|
+
# Add the primary key to the template as being unique (unless it's already there)
|
186
|
+
template[:uniques] = [pk = primary_key.to_sym]
|
187
|
+
template[:all].unshift(pk) unless template[:all].include?(pk)
|
188
|
+
template
|
189
|
+
end
|
190
|
+
|
179
191
|
private
|
180
192
|
|
181
193
|
def self._brick_get_fks
|
@@ -278,16 +290,12 @@ module ActiveRecord
|
|
278
290
|
# Make sure it's a good association name and that the model has that column name
|
279
291
|
next unless (assoc = klass.reflect_on_association(assoc_name))&.klass&.columns&.map(&:name)&.include?(ks.last)
|
280
292
|
|
281
|
-
# So that we can map an association name to any special alias name used in an AREL query
|
282
|
-
ans = (assoc.klass._assoc_names[assoc_name] ||= [])
|
283
|
-
ans << assoc.klass unless ans.include?(assoc.klass)
|
284
293
|
# There is some potential for duplicates when there is an HM-based where in play. De-duplicate if so.
|
285
294
|
has_hm ||= assoc.macro == :has_many
|
286
295
|
join_array[assoc_name] = nil # Store this relation name in our special collection for .joins()
|
287
296
|
end
|
288
297
|
wheres[k] = v.split(',')
|
289
298
|
end
|
290
|
-
# distinct! if has_hm
|
291
299
|
|
292
300
|
# %%% Skip the metadata columns
|
293
301
|
if selects&.empty? # Default to all columns
|
@@ -301,59 +309,101 @@ module ActiveRecord
|
|
301
309
|
if is_add_bts || is_add_hms
|
302
310
|
bts, hms, associatives = ::Brick.get_bts_and_hms(klass)
|
303
311
|
bts.each do |_k, bt|
|
304
|
-
# join_array
|
312
|
+
# join_array will receive this relation name when calling #brick_parse_dsl
|
305
313
|
bt_descrip[bt.first] = [bt.last, bt.last.brick_parse_dsl(join_array, bt.first, translations)]
|
306
314
|
end
|
307
315
|
skip_klass_hms = ::Brick.config.skip_index_hms[klass.name] || {}
|
308
316
|
hms.each do |k, hm|
|
309
317
|
next if skip_klass_hms.key?(k)
|
310
318
|
|
311
|
-
|
312
|
-
hm_counts[k] = nil # Placeholder that will be filled in once we know the proper table alias
|
319
|
+
hm_counts[k] = hm
|
313
320
|
end
|
314
321
|
end
|
315
|
-
|
322
|
+
|
323
|
+
wheres = {}
|
324
|
+
params.each do |k, v|
|
325
|
+
case (ks = k.split('.')).length
|
326
|
+
when 1
|
327
|
+
next unless klass._brick_get_fks.include?(k)
|
328
|
+
when 2
|
329
|
+
assoc_name = ks.first.to_sym
|
330
|
+
# Make sure it's a good association name and that the model has that column name
|
331
|
+
next unless klass.reflect_on_association(assoc_name)&.klass&.columns&.any? { |col| col.name == ks.last }
|
332
|
+
|
333
|
+
join_array[assoc_name] = nil # Store this relation name in our special collection for .joins()
|
334
|
+
end
|
335
|
+
wheres[k] = v.split(',')
|
336
|
+
end
|
337
|
+
|
316
338
|
if join_array.present?
|
317
339
|
left_outer_joins!(join_array) # joins!(join_array)
|
318
340
|
# Without working from a duplicate, touching the AREL ast tree sets the @arel instance variable, which causes the relation to be immutable.
|
319
341
|
(rel_dupe = dup)._arel_alias_names
|
320
342
|
core_selects = selects.dup
|
321
|
-
groups = []
|
322
343
|
chains = rel_dupe._brick_chains
|
323
|
-
id_for_tables = {}
|
344
|
+
id_for_tables = Hash.new { |h, k| h[k] = [] }
|
345
|
+
field_tbl_names = Hash.new { |h, k| h[k] = {} }
|
324
346
|
bt_columns = bt_descrip.each_with_object([]) do |v, s|
|
325
|
-
tbl_name =
|
326
|
-
if (id_col = v.last.first.primary_key) && !id_for_tables.key?(tbl_name
|
327
|
-
|
328
|
-
|
329
|
-
|
347
|
+
tbl_name = field_tbl_names[v.first][v.last.first] ||= shift_or_first(chains[v.last.first])
|
348
|
+
if (id_col = v.last.first.primary_key) && !id_for_tables.key?(v.first) # was tbl_name
|
349
|
+
# Accommodate composite primary key by allowing id_col to come in as an array
|
350
|
+
(id_col.is_a?(Array) ? id_col : [id_col]).each do |id_part|
|
351
|
+
selects << "#{"#{tbl_name}.#{id_part}"} AS \"#{(id_alias = "_brfk_#{v.first}__#{id_part}")}\""
|
352
|
+
id_for_tables[v.first] << id_alias
|
353
|
+
end
|
354
|
+
v.last << id_for_tables[v.first]
|
330
355
|
end
|
331
356
|
if (col_name = v.last[1].last&.last)
|
357
|
+
field_tbl_name = nil
|
332
358
|
v.last[1].map { |x| [translations[x[0..-2].map(&:to_s).join('.')], x.last] }.each_with_index do |sel_col, idx|
|
333
|
-
|
359
|
+
field_tbl_name ||= field_tbl_names[v.first][sel_col.first] ||= shift_or_first(chains[sel_col.first])
|
334
360
|
# col_name is weak when there are multiple, using sel_col.last instead
|
335
|
-
|
336
|
-
selects << "#{unaliased} AS \"#{(col_alias = "_brfk_#{tbl_name2}__#{sel_col.last}")}\""
|
361
|
+
selects << "#{"#{field_tbl_name}.#{sel_col.last}"} AS \"#{(col_alias = "_brfk_#{v.first}__#{sel_col.last}")}\""
|
337
362
|
v.last[1][idx] << col_alias
|
338
363
|
end
|
339
364
|
end
|
340
365
|
end
|
341
|
-
group!(core_selects + groups) if hm_counts.any? # + bt_columns
|
342
366
|
join_array.each do |assoc_name|
|
343
367
|
# %%% Need to support {user: :profile}
|
344
368
|
next unless assoc_name.is_a?(Symbol)
|
345
369
|
|
346
|
-
klass = reflect_on_association(assoc_name)&.klass
|
347
|
-
table_alias = chains[klass].length > 1 ? chains[klass].shift : chains[klass].first
|
370
|
+
table_alias = shift_or_first(chains[klass = reflect_on_association(assoc_name)&.klass])
|
348
371
|
_assoc_names[assoc_name] = [table_alias, klass]
|
349
372
|
end
|
350
|
-
|
351
|
-
|
352
|
-
|
373
|
+
end
|
374
|
+
# Add derived table JOIN for the has_many counts
|
375
|
+
hm_counts.each do |k, hm|
|
376
|
+
associative = nil
|
377
|
+
count_column = if hm.options[:through]
|
378
|
+
fk_col = (associative = associatives[hm.name]).foreign_key
|
379
|
+
hm.foreign_key
|
380
|
+
else
|
381
|
+
fk_col = hm.foreign_key
|
382
|
+
hm.klass.primary_key || '*'
|
383
|
+
end
|
384
|
+
tbl_alias = "_br_#{hm.name}"
|
385
|
+
pri_tbl = hm.active_record
|
386
|
+
if fk_col.is_a?(Array) # Composite key?
|
387
|
+
on_clause = []
|
388
|
+
fk_col.each_with_index { |fk_col_part, idx| on_clause << "#{tbl_alias}.#{fk_col_part} = #{pri_tbl.table_name}.#{pri_tbl.primary_key[idx]}" }
|
389
|
+
joins!("LEFT OUTER
|
390
|
+
JOIN (SELECT #{fk_col.join(', ')}, COUNT(#{count_column}) AS _ct_ FROM #{associative&.table_name || hm.klass.table_name} GROUP BY #{(1..fk_col.length).to_a.join(', ')}) AS #{tbl_alias}
|
391
|
+
ON #{on_clause.join(' AND ')}")
|
392
|
+
else
|
393
|
+
joins!("LEFT OUTER
|
394
|
+
JOIN (SELECT #{fk_col}, COUNT(#{count_column}) AS _ct_ FROM #{associative&.table_name || hm.klass.table_name} GROUP BY 1) AS #{tbl_alias}
|
395
|
+
ON #{tbl_alias}.#{fk_col} = #{pri_tbl.table_name}.#{pri_tbl.primary_key}")
|
353
396
|
end
|
354
397
|
end
|
398
|
+
where!(wheres) unless wheres.empty?
|
355
399
|
wheres unless wheres.empty? # Return the specific parameters that we did use
|
356
400
|
end
|
401
|
+
|
402
|
+
private
|
403
|
+
|
404
|
+
def shift_or_first(ary)
|
405
|
+
ary.length > 1 ? ary.shift : ary.first
|
406
|
+
end
|
357
407
|
end
|
358
408
|
|
359
409
|
module Inheritance
|
@@ -552,27 +602,30 @@ class Object
|
|
552
602
|
# Do the bulk of the has_many / belongs_to processing, and store details about HMT so they can be done at the very last
|
553
603
|
hmts = fks.each_with_object(Hash.new { |h, k| h[k] = [] }) do |fk, hmts|
|
554
604
|
# The key in each hash entry (fk.first) is the constraint name
|
555
|
-
|
556
|
-
inverse_assoc_name = assoc[:inverse]&.fetch(:assoc_name, nil)
|
605
|
+
inverse_assoc_name = (assoc = fk.last)[:inverse]&.fetch(:assoc_name, nil)
|
557
606
|
options = {}
|
558
607
|
singular_table_name = ActiveSupport::Inflector.singularize(assoc[:inverse_table])
|
559
608
|
macro = if assoc[:is_bt]
|
560
609
|
# Try to take care of screwy names if this is a belongs_to going to an STI subclass
|
561
|
-
if (primary_class = assoc.fetch(:primary_class, nil)) &&
|
562
|
-
|
563
|
-
|
564
|
-
|
610
|
+
assoc_name = if (primary_class = assoc.fetch(:primary_class, nil)) &&
|
611
|
+
sti_inverse_assoc = primary_class.reflect_on_all_associations.find do |a|
|
612
|
+
a.macro == :has_many && a.options[:class_name] == self.name && assoc[:fk] = a.foreign_key
|
613
|
+
end
|
614
|
+
sti_inverse_assoc.options[:inverse_of]&.to_s || assoc_name
|
615
|
+
else
|
616
|
+
assoc[:assoc_name]
|
617
|
+
end
|
565
618
|
need_class_name = singular_table_name.underscore != assoc_name
|
566
619
|
need_fk = "#{assoc_name}_id" != assoc[:fk]
|
567
620
|
if (inverse = assoc[:inverse])
|
568
621
|
inverse_assoc_name, _x = _brick_get_hm_assoc_name(relations[assoc[:inverse_table]], inverse)
|
569
622
|
if (has_ones = ::Brick.config.has_ones&.fetch(inverse[:alternate_name].camelize, nil))&.key?(singular_inv_assoc_name = ActiveSupport::Inflector.singularize(inverse_assoc_name))
|
570
623
|
inverse_assoc_name = if has_ones[singular_inv_assoc_name]
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
624
|
+
need_inverse_of = true
|
625
|
+
has_ones[singular_inv_assoc_name]
|
626
|
+
else
|
627
|
+
singular_inv_assoc_name
|
628
|
+
end
|
576
629
|
end
|
577
630
|
end
|
578
631
|
:belongs_to
|
@@ -583,12 +636,12 @@ class Object
|
|
583
636
|
need_fk = "#{ActiveSupport::Inflector.singularize(assoc[:inverse][:inverse_table])}_id" != assoc[:fk]
|
584
637
|
# fks[table_name].find { |other_assoc| other_assoc.object_id != assoc.object_id && other_assoc[:assoc_name] == assoc[assoc_name] }
|
585
638
|
if (has_ones = ::Brick.config.has_ones&.fetch(model_name, nil))&.key?(singular_assoc_name = ActiveSupport::Inflector.singularize(assoc_name))
|
586
|
-
assoc_name = if has_ones[singular_assoc_name]
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
639
|
+
assoc_name = if (custom_assoc_name = has_ones[singular_assoc_name])
|
640
|
+
need_class_name = custom_assoc_name != singular_assoc_name
|
641
|
+
custom_assoc_name
|
642
|
+
else
|
643
|
+
singular_assoc_name
|
644
|
+
end
|
592
645
|
:has_one
|
593
646
|
else
|
594
647
|
:has_many
|
@@ -625,31 +678,34 @@ class Object
|
|
625
678
|
end
|
626
679
|
hmts.each do |hmt_fk, fks|
|
627
680
|
fks.each do |fk|
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
681
|
+
through = fk.first[:assoc_name]
|
682
|
+
hmt_name = if fks.length > 1
|
683
|
+
if fks[0].first[:inverse][:assoc_name] == fks[1].first[:inverse][:assoc_name] # Same BT names pointing back to us? (Most common scenario)
|
684
|
+
"#{hmt_fk}_through_#{fk.first[:assoc_name]}"
|
685
|
+
else # Use BT names to provide uniqueness
|
686
|
+
through = fk.first[:alternate_name].pluralize
|
687
|
+
singular_assoc_name = fk.first[:inverse][:assoc_name].singularize
|
688
|
+
"#{singular_assoc_name}_#{hmt_fk}"
|
689
|
+
end
|
690
|
+
else
|
691
|
+
hmt_fk
|
692
|
+
end
|
693
|
+
source = fk.last unless hmt_name.singularize == fk.last
|
694
|
+
code << " has_many :#{hmt_name}, through: #{(assoc_name = through.to_sym).to_sym.inspect}#{", source: :#{source}" if source}\n"
|
640
695
|
options = { through: assoc_name }
|
641
696
|
options[:source] = source.to_sym if source
|
642
|
-
self.send(:has_many,
|
643
|
-
end
|
644
|
-
end
|
645
|
-
# Not NULLables
|
646
|
-
relation[:cols].each do |col, datatype|
|
647
|
-
if (datatype[3] && ar_pks.exclude?(col) && ::Brick.config.metadata_columns.exclude?(col)) ||
|
648
|
-
::Brick.config.not_nullables.include?("#{matching}.#{col}")
|
649
|
-
code << " validates :#{col}, presence: true\n"
|
650
|
-
self.send(:validates, col.to_sym, { presence: true })
|
697
|
+
self.send(:has_many, hmt_name.to_sym, **options)
|
651
698
|
end
|
652
699
|
end
|
700
|
+
# # Not NULLables
|
701
|
+
# # %%% For the minute we've had to pull this out because it's been troublesome implementing the NotNull validator
|
702
|
+
# relation[:cols].each do |col, datatype|
|
703
|
+
# if (datatype[3] && ar_pks.exclude?(col) && ::Brick.config.metadata_columns.exclude?(col)) ||
|
704
|
+
# ::Brick.config.not_nullables.include?("#{matching}.#{col}")
|
705
|
+
# code << " validates :#{col}, not_null: true\n"
|
706
|
+
# self.send(:validates, col.to_sym, { not_null: true })
|
707
|
+
# end
|
708
|
+
# end
|
653
709
|
end
|
654
710
|
code << "end # model #{model_name}\n\n"
|
655
711
|
end # class definition
|
@@ -668,13 +724,26 @@ class Object
|
|
668
724
|
code << " @#{table_name} = #{model.name}#{model.primary_key ? ".order(#{model.primary_key.inspect})" : '.all'}\n"
|
669
725
|
code << " @#{table_name}.brick_select(params)\n"
|
670
726
|
code << " end\n"
|
727
|
+
self.protect_from_forgery unless: -> { self.request.format.js? }
|
671
728
|
self.define_method :index do
|
672
729
|
::Brick.set_db_schema(params)
|
673
|
-
|
730
|
+
if request.format == :csv # Asking for a template?
|
731
|
+
require 'csv'
|
732
|
+
exported_csv = CSV.generate(force_quotes: false) do |csv_out|
|
733
|
+
model.df_export(model.brick_import_template).each { |row| csv_out << row }
|
734
|
+
end
|
735
|
+
render inline: exported_csv, content_type: request.format
|
736
|
+
return
|
737
|
+
elsif request.format == :js # Asking for JSON?
|
738
|
+
render inline: model.df_export(model.brick_import_template).to_json, content_type: request.format
|
739
|
+
return
|
740
|
+
end
|
741
|
+
|
742
|
+
ar_relation = model.primary_key ? model.order("#{model.table_name}.#{model.primary_key}") : model.all
|
674
743
|
@_brick_params = ar_relation.brick_select(params, (selects = []), (bt_descrip = {}), (hm_counts = {}), (join_array = ::Brick::JoinArray.new))
|
675
744
|
# %%% Add custom HM count columns
|
676
745
|
# %%% What happens when the PK is composite?
|
677
|
-
counts = hm_counts.each_with_object([]) { |v, s| s << "
|
746
|
+
counts = hm_counts.each_with_object([]) { |v, s| s << "_br_#{v.first}._ct_ AS _br_#{v.first}_ct" }
|
678
747
|
# *selects,
|
679
748
|
instance_variable_set("@#{table_name}".to_sym, ar_relation.dup._select!(*selects, *counts))
|
680
749
|
# binding.pry
|
@@ -707,6 +776,22 @@ class Object
|
|
707
776
|
code << " end\n"
|
708
777
|
self.define_method :update do
|
709
778
|
::Brick.set_db_schema(params)
|
779
|
+
|
780
|
+
if request.format == :csv # Importing CSV?
|
781
|
+
require 'csv'
|
782
|
+
# See if internally it's likely a TSV file (tab-separated)
|
783
|
+
tab_counts = []
|
784
|
+
5.times { tab_counts << request.body.readline.count("\t") unless request.body.eof? }
|
785
|
+
request.body.rewind
|
786
|
+
separator = "\t" if tab_counts.length > 0 && tab_counts.uniq.length == 1 && tab_counts.first > 0
|
787
|
+
result = model.df_import(CSV.parse(request.body, { col_sep: separator || :auto }), model.brick_import_template)
|
788
|
+
# render inline: exported_csv, content_type: request.format
|
789
|
+
return
|
790
|
+
# elsif request.format == :js # Asking for JSON?
|
791
|
+
# render inline: model.df_export(true).to_json, content_type: request.format
|
792
|
+
# return
|
793
|
+
end
|
794
|
+
|
710
795
|
instance_variable_set("@#{singular_table_name}".to_sym, (obj = model.find(params[:id].split(','))))
|
711
796
|
obj = obj.first if obj.is_a?(Array)
|
712
797
|
obj.send(:update, send(params_name = params_name.to_sym))
|
@@ -732,7 +817,8 @@ class Object
|
|
732
817
|
|
733
818
|
def _brick_get_hm_assoc_name(relation, hm_assoc)
|
734
819
|
if relation[:hm_counts][hm_assoc[:assoc_name]]&.> 1
|
735
|
-
|
820
|
+
plural = ActiveSupport::Inflector.pluralize(hm_assoc[:alternate_name])
|
821
|
+
[hm_assoc[:alternate_name] == name.underscore ? "#{hm_assoc[:assoc_name].singularize}_#{plural}" : plural, true]
|
736
822
|
else
|
737
823
|
[ActiveSupport::Inflector.pluralize(hm_assoc[:inverse_table]), nil]
|
738
824
|
end
|
@@ -989,18 +1075,16 @@ module Brick
|
|
989
1075
|
|
990
1076
|
return if is_class || ::Brick.config.exclude_hms&.any? { |exclusion| fk[0] == exclusion[0] && fk[1] == exclusion[1] && primary_table == exclusion[2] }
|
991
1077
|
|
992
|
-
|
993
|
-
if (assoc_hm = hms.fetch(cnstr_name, nil))
|
1078
|
+
if (assoc_hm = hms.fetch((hm_cnstr_name = "hm_#{cnstr_name}"), nil))
|
994
1079
|
assoc_hm[:fk] = assoc_hm[:fk].is_a?(String) ? [assoc_hm[:fk], fk[1]] : assoc_hm[:fk].concat(fk[1])
|
995
1080
|
assoc_hm[:alternate_name] = "#{assoc_hm[:alternate_name]}_#{bt_assoc_name}" unless assoc_hm[:alternate_name] == bt_assoc_name
|
996
1081
|
assoc_hm[:inverse] = assoc_bt
|
997
1082
|
else
|
998
|
-
assoc_hm = hms[
|
1083
|
+
assoc_hm = hms[hm_cnstr_name] = { is_bt: false, fk: fk[1], assoc_name: fk[0], alternate_name: bt_assoc_name, inverse_table: fk[0], inverse: assoc_bt }
|
999
1084
|
hm_counts = relation.fetch(:hm_counts) { relation[:hm_counts] = {} }
|
1000
1085
|
hm_counts[fk[0]] = hm_counts.fetch(fk[0]) { 0 } + 1
|
1001
1086
|
end
|
1002
1087
|
assoc_bt[:inverse] = assoc_hm
|
1003
|
-
# hms[cnstr_name] << { is_bt: false, fk: fk[1], assoc_name: fk[0], alternate_name: bt_assoc_name, inverse_table: fk[0] }
|
1004
1088
|
end
|
1005
1089
|
end
|
1006
1090
|
end
|
@@ -64,6 +64,14 @@ module Brick
|
|
64
64
|
is_template_exists
|
65
65
|
end
|
66
66
|
|
67
|
+
def path_keys(fk_name, obj_name, pk)
|
68
|
+
if fk_name.is_a?(Array) && pk.is_a?(Array) # Composite keys?
|
69
|
+
fk_name.zip(pk.map { |pk_part| "#{obj_name}.#{pk_part}" })
|
70
|
+
else
|
71
|
+
[[fk_name, "#{obj_name}.#{pk}"]]
|
72
|
+
end.map { |x| "#{x.first}: #{x.last}"}.join(', ')
|
73
|
+
end
|
74
|
+
|
67
75
|
alias :_brick_find_template :find_template
|
68
76
|
def find_template(*args, **options)
|
69
77
|
return _brick_find_template(*args, **options) unless @_brick_model
|
@@ -72,36 +80,36 @@ module Brick
|
|
72
80
|
pk = @_brick_model.primary_key
|
73
81
|
obj_name = model_name.underscore
|
74
82
|
table_name = model_name.pluralize.underscore
|
83
|
+
template_link = nil
|
75
84
|
bts, hms, associatives = ::Brick.get_bts_and_hms(@_brick_model) # This gets BT and HM and also has_many :through (HMT)
|
76
|
-
hms_columns =
|
85
|
+
hms_columns = [] # Used for 'index'
|
77
86
|
skip_klass_hms = ::Brick.config.skip_index_hms[model_name] || {}
|
78
87
|
hms_headers = hms.each_with_object([]) do |hm, s|
|
79
|
-
hm_assoc = hm.last
|
80
|
-
if
|
81
|
-
|
82
|
-
|
83
|
-
"'#{associative.name}.#{associative.foreign_key}'"
|
84
|
-
else
|
85
|
-
hm_assoc.foreign_key
|
86
|
-
end
|
87
|
-
hms_columns << if hm_assoc.macro == :has_many
|
88
|
-
set_ct = if skip_klass_hms.key?((assoc_name = hm.first).to_sym)
|
89
|
-
'nil'
|
88
|
+
hm_stuff = [(hm_assoc = hm.last), "H#{hm_assoc.macro == :has_one ? 'O' : 'M'}#{'T' if hm_assoc.options[:through]}", (assoc_name = hm.first)]
|
89
|
+
hm_fk_name = if hm_assoc.options[:through]
|
90
|
+
associative = associatives[hm_assoc.name]
|
91
|
+
"'#{associative.name}.#{associative.foreign_key}'"
|
90
92
|
else
|
91
|
-
|
93
|
+
hm_assoc.foreign_key
|
92
94
|
end
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
95
|
+
if args.first == 'index'
|
96
|
+
hms_columns << if hm_assoc.macro == :has_many
|
97
|
+
set_ct = if skip_klass_hms.key?(assoc_name.to_sym)
|
98
|
+
'nil'
|
99
|
+
else
|
100
|
+
# Postgres column names are limited to 63 characters
|
101
|
+
attrib_name = "_br_#{assoc_name}_ct"[0..62]
|
102
|
+
"#{obj_name}.#{attrib_name} || 0"
|
103
|
+
end
|
104
|
+
"<%= ct = #{set_ct}
|
105
|
+
link_to \"#\{ct || 'View'\} #{assoc_name}\", #{hm_assoc.klass.name.underscore.pluralize}_path({ #{path_keys(hm_fk_name, obj_name, pk)} }) unless ct&.zero? %>\n"
|
98
106
|
else # has_one
|
99
|
-
"
|
100
|
-
<%= obj = #{obj_name}.#{hm.first}; link_to(obj.brick_descrip, obj) if obj %>
|
101
|
-
</td>\n"
|
107
|
+
"<%= obj = #{obj_name}.#{hm.first}; link_to(obj.brick_descrip, obj) if obj %>\n"
|
102
108
|
end
|
109
|
+
elsif args.first == 'show'
|
110
|
+
hm_stuff << "<%= link_to '#{assoc_name}', #{hm_assoc.klass.name.underscore.pluralize}_path({ #{path_keys(hm_fk_name, "@#{obj_name}&.first&", pk)} }) %>\n"
|
103
111
|
end
|
104
|
-
s <<
|
112
|
+
s << hm_stuff
|
105
113
|
end
|
106
114
|
|
107
115
|
schema_options = ::Brick.db_schemas.each_with_object(+'') { |v, s| s << "<option value=\"#{v}\">#{v}</option>" }.html_safe
|
@@ -110,6 +118,13 @@ module Brick
|
|
110
118
|
table_options = (::Brick.relations.keys - ::Brick.config.exclude_tables)
|
111
119
|
.each_with_object(+'') { |v, s| s << "<option value=\"#{v.underscore.pluralize}\">#{v}</option>" }.html_safe
|
112
120
|
css = +"<style>
|
121
|
+
#dropper {
|
122
|
+
background-color: #eee;
|
123
|
+
}
|
124
|
+
#btnImport {
|
125
|
+
display: none;
|
126
|
+
}
|
127
|
+
|
113
128
|
table {
|
114
129
|
border-collapse: collapse;
|
115
130
|
margin: 25px 0;
|
@@ -121,9 +136,12 @@ table {
|
|
121
136
|
|
122
137
|
table thead tr th, table tr th {
|
123
138
|
background-color: #009879;
|
124
|
-
color: #
|
139
|
+
color: #fff;
|
125
140
|
text-align: left;
|
126
141
|
}
|
142
|
+
table thead tr th a, table tr th a {
|
143
|
+
color: #80FFB8;
|
144
|
+
}
|
127
145
|
|
128
146
|
table th, table td {
|
129
147
|
padding: 0.2em 0.5em;
|
@@ -132,6 +150,9 @@ table th, table td {
|
|
132
150
|
.show-field {
|
133
151
|
background-color: #004998;
|
134
152
|
}
|
153
|
+
.show-field a {
|
154
|
+
color: #80B8D2;
|
155
|
+
}
|
135
156
|
|
136
157
|
table tbody tr {
|
137
158
|
border-bottom: thin solid #dddddd;
|
@@ -244,11 +265,107 @@ function changeout(href, param, value) {
|
|
244
265
|
</script>"
|
245
266
|
inline = case args.first
|
246
267
|
when 'index'
|
268
|
+
obj_pk = if pk&.is_a?(Array) # Composite primary key?
|
269
|
+
"[#{pk.map { |pk_part| "#{obj_name}.#{pk_part}" }.join(', ')}]"
|
270
|
+
elsif pk
|
271
|
+
"#{obj_name}.#{pk}"
|
272
|
+
end
|
273
|
+
if Object.const_defined?('DutyFree')
|
274
|
+
template_link = "
|
275
|
+
<%= link_to 'CSV', #{table_name}_path(format: :csv) %> <a href=\"#\" id=\"sheetsLink\">Sheets</a>
|
276
|
+
<div id=\"dropper\" contenteditable=\"true\"></div>
|
277
|
+
<input type=\"button\" id=\"btnImport\" value=\"Import\">
|
278
|
+
|
279
|
+
<script>
|
280
|
+
var dropperDiv = document.getElementById(\"dropper\");
|
281
|
+
var btnImport = document.getElementById(\"btnImport\");
|
282
|
+
var droppedTSV;
|
283
|
+
if (dropperDiv) { // Other interesting events: blur keyup input
|
284
|
+
dropperDiv.addEventListener(\"paste\", function (evt) {
|
285
|
+
droppedTSV = evt.clipboardData.getData('text/plain');
|
286
|
+
var html = evt.clipboardData.getData('text/html');
|
287
|
+
var tbl = html.substring(html.indexOf(\"<tbody>\") + 7, html.lastIndexOf(\"</tbody>\"));
|
288
|
+
console.log(tbl);
|
289
|
+
btnImport.style.display = droppedTSV.length > 0 ? \"block\" : \"none\";
|
290
|
+
});
|
291
|
+
btnImport.addEventListener(\"click\", function () {
|
292
|
+
fetch(changeout(<%= #{obj_name}_path(-1, format: :csv).inspect.html_safe %>, \"_brick_schema\", brickSchema), {
|
293
|
+
method: 'PATCH',
|
294
|
+
headers: { 'Content-Type': 'text/tab-separated-values' },
|
295
|
+
body: droppedTSV
|
296
|
+
}).then(function (tsvResponse) {
|
297
|
+
btnImport.style.display = \"none\";
|
298
|
+
console.log(\"toaster\", tsvResponse);
|
299
|
+
});
|
300
|
+
});
|
301
|
+
}
|
302
|
+
var sheetUrl;
|
303
|
+
var spreadsheetId;
|
304
|
+
var sheetsLink = document.getElementById(\"sheetsLink\");
|
305
|
+
function gapiLoaded() {
|
306
|
+
// Have a click on the sheets link to bring up the sign-in window. (Must happen from some kind of user click.)
|
307
|
+
sheetsLink.addEventListener(\"click\", async function (evt) {
|
308
|
+
evt.preventDefault();
|
309
|
+
await gapi.load(\"client\", function () {
|
310
|
+
gapi.client.init({ // Load the discovery doc to initialize the API
|
311
|
+
clientId: \"487319557829-fgj4u660igrpptdji7ev0r5hb6kh05dh.apps.googleusercontent.com\",
|
312
|
+
scope: \"https://www.googleapis.com/auth/spreadsheets https://www.googleapis.com/auth/drive.file\",
|
313
|
+
discoveryDocs: [\"https://sheets.googleapis.com/$discovery/rest?version=v4\"]
|
314
|
+
}).then(function () {
|
315
|
+
gapi.auth2.getAuthInstance().isSignedIn.listen(updateSignInStatus);
|
316
|
+
updateSignInStatus(gapi.auth2.getAuthInstance().isSignedIn.get());
|
317
|
+
});
|
318
|
+
});
|
319
|
+
});
|
320
|
+
}
|
321
|
+
|
322
|
+
async function updateSignInStatus(isSignedIn) {
|
323
|
+
if (isSignedIn) {
|
324
|
+
console.log(\"turds!\");
|
325
|
+
await gapi.client.sheets.spreadsheets.create({
|
326
|
+
properties: {
|
327
|
+
title: #{table_name.inspect},
|
328
|
+
},
|
329
|
+
sheets: [
|
330
|
+
// sheet1, sheet2, sheet3
|
331
|
+
]
|
332
|
+
}).then(function (response) {
|
333
|
+
sheetUrl = response.result.spreadsheetUrl;
|
334
|
+
spreadsheetId = response.result.spreadsheetId;
|
335
|
+
sheetsLink.setAttribute(\"href\", sheetUrl); // response.result.spreadsheetUrl
|
336
|
+
console.log(\"x1\", sheetUrl);
|
337
|
+
|
338
|
+
// Get JSON data
|
339
|
+
fetch(changeout(<%= #{table_name}_path(format: :js).inspect.html_safe %>, \"_brick_schema\", brickSchema)).then(function (response) {
|
340
|
+
response.json().then(function (data) {
|
341
|
+
gapi.client.sheets.spreadsheets.values.append({
|
342
|
+
spreadsheetId: spreadsheetId,
|
343
|
+
range: \"Sheet1\",
|
344
|
+
valueInputOption: \"RAW\",
|
345
|
+
insertDataOption: \"INSERT_ROWS\"
|
346
|
+
}, {
|
347
|
+
range: \"Sheet1\",
|
348
|
+
majorDimension: \"ROWS\",
|
349
|
+
values: data,
|
350
|
+
}).then(function (response2) {
|
351
|
+
// console.log(\"beefcake\", response2);
|
352
|
+
});
|
353
|
+
});
|
354
|
+
});
|
355
|
+
});
|
356
|
+
window.open(sheetUrl, '_blank');
|
357
|
+
}
|
358
|
+
}
|
359
|
+
</script>
|
360
|
+
<script async defer src=\"https://apis.google.com/js/api.js\" onload=\"gapiLoaded()\"></script>
|
361
|
+
"
|
362
|
+
end
|
247
363
|
"#{css}
|
248
364
|
<p style=\"color: green\"><%= notice %></p>#{"
|
249
365
|
<select id=\"schema\">#{schema_options}</select>" if ::Brick.db_schemas.length > 1}
|
250
366
|
<select id=\"tbl\">#{table_options}</select>
|
251
|
-
<h1>#{model_name.pluralize}</h1
|
367
|
+
<h1>#{model_name.pluralize}</h1>#{template_link}
|
368
|
+
|
252
369
|
<% if @_brick_params&.present? %><h3>where <%= @_brick_params.each_with_object([]) { |v, s| s << \"#\{v.first\} = #\{v.last.inspect\}\" }.join(', ') %></h3><% end %>
|
253
370
|
<table id=\"#{table_name}\">
|
254
371
|
<thead><tr>#{'<th></th>' if pk}
|
@@ -256,26 +373,27 @@ function changeout(href, param, value) {
|
|
256
373
|
<% next if col == '#{pk}' || ::Brick.config.metadata_columns.include?(col) %>
|
257
374
|
<th>
|
258
375
|
<% if (bt = bts[col]) %>
|
259
|
-
BT <%=
|
376
|
+
BT <%= bt[1].bt_link(bt.first) %>
|
260
377
|
<% else %>
|
261
378
|
<%= col %>
|
262
379
|
<% end %>
|
263
380
|
</th>
|
264
381
|
<% end %>
|
265
|
-
|
382
|
+
<%# Consider getting the name from the association -- h.first.name -- if a more \"friendly\" alias should be used for a screwy table name %>
|
383
|
+
#{hms_headers.map { |h| "<th>#{h[1]} <%= link_to('#{h[2]}', #{h.first.klass.name.underscore.pluralize}_path) %></th>\n" }.join}
|
266
384
|
</tr></thead>
|
267
385
|
|
268
386
|
<tbody>
|
269
387
|
<% @#{table_name}.each do |#{obj_name}| %>
|
270
388
|
<tr>#{"
|
271
|
-
<td><%= link_to '⇛', #{obj_name}_path(#{
|
389
|
+
<td><%= link_to '⇛', #{obj_name}_path(#{obj_pk}), { class: 'big-arrow' } %></td>" if obj_pk}
|
272
390
|
<% #{obj_name}.attributes.each do |k, val| %>
|
273
391
|
<% next if k == '#{pk}' || ::Brick.config.metadata_columns.include?(k) || k.start_with?('_brfk_') || (k.start_with?('_br_') && k.end_with?('_ct')) %>
|
274
392
|
<td>
|
275
393
|
<% if (bt = bts[k]) %>
|
276
|
-
<%# binding.pry
|
277
|
-
<% bt_txt = bt[1].brick_descrip(#{obj_name}, @_brick_bt_descrip[bt.first][1].map { |z| #{obj_name}.send(z.last) }, @_brick_bt_descrip[bt.first][2]) %>
|
278
|
-
<% bt_id_col = @_brick_bt_descrip[bt.first][2]; bt_id = #{obj_name}.send(bt_id_col) if bt_id_col %>
|
394
|
+
<%# binding.pry # Postgres column names are limited to 63 characters %>
|
395
|
+
<% bt_txt = bt[1].brick_descrip(#{obj_name}, @_brick_bt_descrip[bt.first][1].map { |z| #{obj_name}.send(z.last[0..62]) }, @_brick_bt_descrip[bt.first][2]) %>
|
396
|
+
<% bt_id_col = @_brick_bt_descrip[bt.first][2]; bt_id = #{obj_name}.send(*bt_id_col) if bt_id_col&.present? %>
|
279
397
|
<%= bt_id ? link_to(bt_txt, send(\"#\{bt_obj_path_base = bt[1].name.underscore\}_path\".to_sym, bt_id)) : bt_txt %>
|
280
398
|
<%#= Previously was: bt_obj = bt[1].find_by(bt[2] => val); link_to(bt_obj.brick_descrip, send(\"#\{bt_obj_path_base = bt[1].name.underscore\}_path\".to_sym, bt_obj.send(bt[1].primary_key.to_sym))) if bt_obj %>
|
281
399
|
<% else %>
|
@@ -283,8 +401,7 @@ function changeout(href, param, value) {
|
|
283
401
|
<% end %>
|
284
402
|
</td>
|
285
403
|
<% end %>
|
286
|
-
#{hms_columns}
|
287
|
-
<!-- td>X</td -->
|
404
|
+
#{hms_columns.each_with_object(+'') { |hm_col, s| s << "<td>#{hm_col}</td>" }}
|
288
405
|
</tr>
|
289
406
|
</tbody>
|
290
407
|
<% end %>
|
@@ -301,23 +418,27 @@ function changeout(href, param, value) {
|
|
301
418
|
<%= link_to '(See all #{obj_name.pluralize})', #{table_name}_path %>
|
302
419
|
<% if obj %>
|
303
420
|
<%= # path_options = [obj.#{pk}]
|
304
|
-
# path_options << { '_brick_schema': } if
|
421
|
+
# path_options << { '_brick_schema': } if
|
305
422
|
# url = send(:#{model_name.underscore}_path, obj.#{pk})
|
306
|
-
form_for(obj) do |f| %>
|
423
|
+
form_for(obj.becomes(#{model_name})) do |f| %>
|
307
424
|
<table>
|
308
|
-
<%
|
425
|
+
<% has_fields = false
|
426
|
+
@#{obj_name}.first.attributes.each do |k, val| %>
|
309
427
|
<tr>
|
428
|
+
<%# %%% Accommodate composite keys %>
|
310
429
|
<% next if k == '#{pk}' || ::Brick.config.metadata_columns.include?(k) %>
|
311
430
|
<th class=\"show-field\">
|
312
|
-
<%
|
431
|
+
<% has_fields = true
|
432
|
+
if (bt = bts[k])
|
313
433
|
# Add a final member in this array with descriptive options to be used in <select> drop-downs
|
314
434
|
bt_name = bt[1].name
|
315
435
|
# %%% Only do this if the user has permissions to edit this bt field
|
316
436
|
if bt.length < 4
|
317
437
|
bt << (option_detail = [[\"(No #\{bt_name\} chosen)\", '^^^brick_NULL^^^']])
|
318
|
-
|
438
|
+
# %%% Accommodate composite keys for obj.pk at the end here
|
439
|
+
bt[1].order(obj_pk = bt[1].primary_key).each { |obj| option_detail << [obj.brick_descrip(nil, obj_pk), obj.send(obj_pk)] }
|
319
440
|
end %>
|
320
|
-
BT <%=
|
441
|
+
BT <%= bt[1].bt_link(bt.first) %>
|
321
442
|
<% else %>
|
322
443
|
<%= k %>
|
323
444
|
<% end %>
|
@@ -348,26 +469,34 @@ function changeout(href, param, value) {
|
|
348
469
|
<% end %>
|
349
470
|
</td>
|
350
471
|
</tr>
|
472
|
+
<% end
|
473
|
+
if has_fields %>
|
474
|
+
<tr><td colspan=\"2\" class=\"right\"><%= f.submit %></td></tr>
|
475
|
+
<% else %>
|
476
|
+
<tr><td colspan=\"2\">(No displayable fields)</td></tr>
|
351
477
|
<% end %>
|
352
|
-
<tr><td colspan=\"2\" class=\"right\"><%= f.submit %></td></tr>
|
353
478
|
</table>
|
354
479
|
<% end %>
|
355
480
|
|
356
|
-
#{hms_headers.
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
481
|
+
#{hms_headers.each_with_object(+'') do |hm, s|
|
482
|
+
if (pk = hm.first.klass.primary_key)
|
483
|
+
s << "<table id=\"#{hm_name = hm.first.name.to_s}\">
|
484
|
+
<tr><th>#{hm[3]}</th></tr>
|
485
|
+
<% collection = @#{obj_name}.first.#{hm_name}
|
486
|
+
collection = collection.is_a?(ActiveRecord::Associations::CollectionProxy) ? collection.order(#{pk.inspect}) : [collection]
|
487
|
+
if collection.empty? %>
|
488
|
+
<tr><td>(none)</td></tr>
|
489
|
+
<% else %>
|
490
|
+
<% collection.uniq.each do |#{hm_singular_name = hm_name.singularize.underscore}| %>
|
491
|
+
<%# %%% accommodate composite primary key %>
|
492
|
+
<tr><td><%= link_to(#{hm_singular_name}.brick_descrip, #{hm.first.klass.name.underscore}_path(#{hm_singular_name}.#{pk})) %></td></tr>
|
493
|
+
<% end %>
|
494
|
+
<% end %>
|
495
|
+
</table>"
|
496
|
+
else
|
497
|
+
s
|
498
|
+
end
|
499
|
+
end}
|
371
500
|
<% end %>
|
372
501
|
#{script}"
|
373
502
|
|
data/lib/brick/version_number.rb
CHANGED
data/lib/brick.rb
CHANGED
@@ -105,9 +105,6 @@ module Brick
|
|
105
105
|
bts, hms = model.reflect_on_all_associations.each_with_object([{}, {}]) do |a, s|
|
106
106
|
next if !const_defined?(a.name.to_s.singularize.camelize) && ::Brick.config.exclude_tables.include?(a.plural_name)
|
107
107
|
|
108
|
-
# So that we can map an association name to any special alias name used in an AREL query
|
109
|
-
ans = (model._assoc_names[a.name] ||= [])
|
110
|
-
ans << a.klass unless ans.include?(a.klass)
|
111
108
|
case a.macro
|
112
109
|
when :belongs_to
|
113
110
|
s.first[a.foreign_key] = [a.name, a.klass]
|
@@ -129,9 +126,7 @@ module Brick
|
|
129
126
|
skip_hms[hmt.last.name] = nil
|
130
127
|
end
|
131
128
|
end
|
132
|
-
skip_hms.each
|
133
|
-
puts hms.delete(k).inspect
|
134
|
-
end
|
129
|
+
skip_hms.each { |k, _v| hms.delete(k) }
|
135
130
|
[bts, hms, associatives]
|
136
131
|
end
|
137
132
|
|
@@ -427,9 +422,7 @@ ActiveSupport.on_load(:active_record) do
|
|
427
422
|
end
|
428
423
|
|
429
424
|
result = result.map do |attributes|
|
430
|
-
|
431
|
-
|
432
|
-
columns.zip(values).map do |column, value|
|
425
|
+
columns.zip(klass.initialize_attributes(attributes).values).map do |column, value|
|
433
426
|
column.type_cast(value)
|
434
427
|
end
|
435
428
|
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.
|
4
|
+
version: 1.0.24
|
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-05-
|
11
|
+
date: 2022-05-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|