brick 1.0.102 → 1.0.104
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 +29 -14
- data/lib/brick/frameworks/rails/engine.rb +161 -92
- data/lib/brick/frameworks/rails/form_tags.rb +87 -76
- data/lib/brick/version_number.rb +1 -1
- data/lib/generators/brick/install_generator.rb +6 -4
- metadata +2 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6d30161a8558282149a49e7eafbd43bb175ce95574178c65a75323eaacf96422
|
4
|
+
data.tar.gz: 6d56c5e77c2a0d120bc8e878bde9d33fdfa7d58bed690a21fea176d5d6b55d50
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 14bfffec6fd768d4b3abff2b3ceaeb2a2dca29b167edd64c2e57a63c72eaa70bf46fc8056af25fca86812bfac63d3b793bdeaf7f13a8c2ba7834ac9e65f1fb16
|
7
|
+
data.tar.gz: 97f7c94051bb068c4d8bdb5e847e53576c8ebbe18d5c4c93e12d52566008ac612bb40f7088ba81fea21337a3c13c29f366fb993b77f2f88f9fbddea4ffb95982
|
data/lib/brick/extensions.rb
CHANGED
@@ -77,14 +77,13 @@ module ActiveRecord
|
|
77
77
|
def self.brick_get_dsl
|
78
78
|
# If there's no DSL yet specified, just try to find the first usable column on this model
|
79
79
|
unless (dsl = ::Brick.config.model_descrips[name])
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
end
|
80
|
+
skip_columns = _brick_get_fks + (::Brick.config.metadata_columns || []) + [primary_key]
|
81
|
+
dsl = if (descrip_col = columns.find { |c| [:boolean, :binary, :xml].exclude?(c.type) && skip_columns.exclude?(c.name) })
|
82
|
+
"[#{descrip_col.name}]"
|
83
|
+
elsif (pk_parts = self.primary_key.is_a?(Array) ? self.primary_key : [self.primary_key])
|
84
|
+
"#{name} ##{pk_parts.map { |pk_part| "[#{pk_part}]" }.join(', ')}"
|
85
|
+
end
|
86
|
+
::Brick.config.model_descrips[name] = dsl
|
88
87
|
end
|
89
88
|
dsl
|
90
89
|
end
|
@@ -129,7 +128,7 @@ module ActiveRecord
|
|
129
128
|
translations[parts[0..-2].join('.')] = klass
|
130
129
|
end
|
131
130
|
if klass&.column_names.exclude?(parts.last) &&
|
132
|
-
|
131
|
+
(klass = (orig_class = klass).reflect_on_association(possible_dsl = parts.pop.to_sym)&.klass)
|
133
132
|
if prefix.empty? # Custom columns start with an empty prefix
|
134
133
|
prefix << parts.shift until parts.empty?
|
135
134
|
end
|
@@ -258,11 +257,11 @@ module ActiveRecord
|
|
258
257
|
assoc_html_name ? "#{assoc_name}-#{link}".html_safe : link
|
259
258
|
end
|
260
259
|
|
261
|
-
def self._brick_index(mode = nil)
|
260
|
+
def self._brick_index(mode = nil, separator = '_')
|
262
261
|
tbl_parts = ((mode == :singular) ? table_name.singularize : table_name).split('.')
|
263
262
|
tbl_parts.shift if ::Brick.apartment_multitenant && tbl_parts.length > 1 && tbl_parts.first == ::Brick.apartment_default_tenant
|
264
263
|
tbl_parts.unshift(::Brick.config.path_prefix) if ::Brick.config.path_prefix
|
265
|
-
index = tbl_parts.map(&:underscore).join(
|
264
|
+
index = tbl_parts.map(&:underscore).join(separator)
|
266
265
|
# Rails applies an _index suffix to that route when the resource name is singular
|
267
266
|
index << '_index' if mode != :singular && index == index.singularize
|
268
267
|
index
|
@@ -397,6 +396,8 @@ module ActiveRecord
|
|
397
396
|
end
|
398
397
|
|
399
398
|
class Relation
|
399
|
+
attr_accessor :_brick_page_num
|
400
|
+
|
400
401
|
# Links from ActiveRecord association pathing names over to real table correlation names
|
401
402
|
# that get chosen when the AREL AST tree is walked.
|
402
403
|
def brick_links
|
@@ -786,8 +787,21 @@ JOIN (SELECT #{hm_selects.map { |s| "#{'br_t0.' if from_clause}#{s}" }.join(', '
|
|
786
787
|
end
|
787
788
|
self.order_values |= final_order_by # Same as: order!(*final_order_by)
|
788
789
|
end
|
789
|
-
|
790
|
-
|
790
|
+
if (page = params['_brick_page']&.to_i)
|
791
|
+
page = 1 if page < 1
|
792
|
+
limit = params['_brick_page_size'] || 1000
|
793
|
+
offset = (page - 1) * limit.to_i
|
794
|
+
else
|
795
|
+
offset = params['_brick_offset']
|
796
|
+
limit = params['_brick_limit']
|
797
|
+
end
|
798
|
+
if offset.is_a?(Numeric) || offset&.present?
|
799
|
+
offset = offset.to_i
|
800
|
+
self.offset_value = offset unless offset == 0
|
801
|
+
@_brick_page_num = (offset / limit.to_i) + 1 if limit&.!= 0 && (offset % limit.to_i) == 0
|
802
|
+
end
|
803
|
+
# By default just 1000 rows (Like doing: limit!(1000) but this way is compatible with AR <= 4.2)
|
804
|
+
self.limit_value = limit&.to_i || 1000 unless limit.is_a?(String) && limit.empty?
|
791
805
|
wheres unless wheres.empty? # Return the specific parameters that we did use
|
792
806
|
end
|
793
807
|
|
@@ -805,7 +819,8 @@ JOIN (SELECT #{hm_selects.map { |s| "#{'br_t0.' if from_clause}#{s}" }.join(', '
|
|
805
819
|
alias _brick_find_sti_class find_sti_class
|
806
820
|
def find_sti_class(type_name)
|
807
821
|
if ::Brick.sti_models.key?(type_name ||= name)
|
808
|
-
::Brick.sti_models[type_name].fetch(:base, nil) || _brick_find_sti_class(type_name)
|
822
|
+
# Used to be: ::Brick.sti_models[type_name].fetch(:base, nil) || _brick_find_sti_class(type_name)
|
823
|
+
_brick_find_sti_class(type_name)
|
809
824
|
else
|
810
825
|
# This auto-STI is more of a brute-force approach, building modules where needed
|
811
826
|
# The more graceful alternative is the overload of ActiveSupport::Dependencies#autoload_module! found below
|
@@ -29,6 +29,54 @@ module Brick
|
|
29
29
|
var finalParams = Object.keys(params).reduce(function (s, v) { if (params[v]) s.push(v + \"=\" + params[v]); return s; }, []).join(\"&\");
|
30
30
|
return hrefParts[0] + (finalParams.length > 0 ? \"?\" + finalParams : \"\");
|
31
31
|
}
|
32
|
+
|
33
|
+
// This PageTransitionEvent fires when the page first loads, as well as after any other history
|
34
|
+
// transition such as when using the browser's Back and Forward buttons.
|
35
|
+
window.addEventListener(\"pageshow\", linkSchemas);
|
36
|
+
var brickSchema;
|
37
|
+
function linkSchemas() {
|
38
|
+
var schemaSelect = document.getElementById(\"schema\");
|
39
|
+
var tblSelect = document.getElementById(\"tbl\");
|
40
|
+
if (tblSelect) { // Always present
|
41
|
+
// Used to be: var i = # {::Brick.config.path_prefix ? '0' : 'schemaSelect ? 1 : 0'},
|
42
|
+
var changeoutList = changeout(location.href);
|
43
|
+
for (var i = 0; i < changeoutList.length; ++i) {
|
44
|
+
tblSelect.value = changeoutList[i];
|
45
|
+
if (tblSelect.value !== \"\") break;
|
46
|
+
}
|
47
|
+
|
48
|
+
tblSelect.addEventListener(\"change\", function () {
|
49
|
+
var lhr = changeout(location.href, null, this.value);
|
50
|
+
if (brickSchema) lhr = changeout(lhr, \"_brick_schema\", schemaSelect.value);
|
51
|
+
location.href = lhr;
|
52
|
+
});
|
53
|
+
}
|
54
|
+
|
55
|
+
if (schemaSelect) { // First drop-down is only present if multitenant
|
56
|
+
if (brickSchema = changeout(location.href, \"_brick_schema\")) {
|
57
|
+
[... document.getElementsByTagName(\"A\")].forEach(function (a) { a.href = changeout(a.href, \"_brick_schema\", brickSchema); });
|
58
|
+
}
|
59
|
+
if (schemaSelect.options.length > 1) {
|
60
|
+
schemaSelect.value = brickSchema || \"public\";
|
61
|
+
schemaSelect.addEventListener(\"change\", function () {
|
62
|
+
// If there's an ID then remove it (trim after selected table)
|
63
|
+
location.href = changeout(location.href, \"_brick_schema\", this.value, tblSelect.value);
|
64
|
+
});
|
65
|
+
}
|
66
|
+
}
|
67
|
+
tblSelect.focus();
|
68
|
+
|
69
|
+
[... document.getElementsByTagName(\"FORM\")].forEach(function (form) {
|
70
|
+
if (brickSchema)
|
71
|
+
form.action = changeout(form.action, \"_brick_schema\", brickSchema);
|
72
|
+
form.addEventListener('submit', function (ev) {
|
73
|
+
[... ev.target.getElementsByTagName(\"SELECT\")].forEach(function (select) {
|
74
|
+
if (select.value === \"^^^brick_NULL^^^\") select.value = null;
|
75
|
+
});
|
76
|
+
return true;
|
77
|
+
});
|
78
|
+
});
|
79
|
+
};
|
32
80
|
"
|
33
81
|
|
34
82
|
# paths['app/models'] << 'lib/brick/frameworks/active_record/models'
|
@@ -168,17 +216,9 @@ module Brick
|
|
168
216
|
end
|
169
217
|
"<script>
|
170
218
|
#{JS_CHANGEOUT}
|
171
|
-
window.addEventListener(\"load\", linkSchemas);
|
172
219
|
document.addEventListener(\"turbo:render\", linkSchemas);
|
173
220
|
window.addEventListener(\"popstate\", linkSchemas);
|
174
221
|
// [... document.getElementsByTagName('turbo-frame')].forEach(function (a) { a.addEventListener(\"turbo:frame-render\", linkSchemas); });
|
175
|
-
function linkSchemas() {
|
176
|
-
brickSchema = changeout(location.href, \"_brick_schema\");
|
177
|
-
if (brickSchema) {
|
178
|
-
[... document.getElementsByTagName(\"A\")].forEach(function (a) { a.href = changeout(a.href, \"_brick_schema\", brickSchema); });
|
179
|
-
[... document.getElementsByTagName(\"FORM\")].forEach(function (form) { form.action = changeout(form.action, \"_brick_schema\", brickSchema); });
|
180
|
-
}
|
181
|
-
}
|
182
222
|
</script>
|
183
223
|
#{_brick_content}".html_safe
|
184
224
|
end
|
@@ -188,8 +228,8 @@ function linkSchemas() {
|
|
188
228
|
# When available, add a clickable brick icon to go to the Brick version of the page
|
189
229
|
PanelComponent.class_exec do
|
190
230
|
alias _brick_init initialize
|
191
|
-
def initialize(*args)
|
192
|
-
_brick_init(*args)
|
231
|
+
def initialize(*args, **kwargs)
|
232
|
+
_brick_init(*args, **kwargs)
|
193
233
|
@name = BrickTitle.new(@name, self)
|
194
234
|
end
|
195
235
|
end
|
@@ -223,6 +263,16 @@ function linkSchemas() {
|
|
223
263
|
_brick_resource_view_path
|
224
264
|
end
|
225
265
|
end
|
266
|
+
|
267
|
+
module Concerns::HasFields
|
268
|
+
class_methods do
|
269
|
+
alias _brick_field field
|
270
|
+
def field(name, *args, **kwargs, &block)
|
271
|
+
kwargs.merge!(args.pop) if args.last.is_a?(Hash)
|
272
|
+
_brick_field(name, **kwargs, &block)
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
226
276
|
end # module Avo
|
227
277
|
|
228
278
|
# Steer any Avo-related controller/action based URL lookups to the Avo RouteSet
|
@@ -288,7 +338,14 @@ function linkSchemas() {
|
|
288
338
|
else
|
289
339
|
[[fk_name, pk.length == 1 ? pk.first : pk.inspect]]
|
290
340
|
end
|
291
|
-
|
341
|
+
if hm_assoc.options.key?(:as)
|
342
|
+
poly_type = if hm_assoc.active_record.column_names.include?(hm_assoc.active_record.inheritance_column)
|
343
|
+
'[sti_type]'
|
344
|
+
else
|
345
|
+
hm_assoc.active_record.name
|
346
|
+
end
|
347
|
+
keys << [hm_assoc.inverse_of.foreign_type, poly_type]
|
348
|
+
end
|
292
349
|
keys.to_h
|
293
350
|
end
|
294
351
|
|
@@ -362,9 +419,14 @@ function linkSchemas() {
|
|
362
419
|
end
|
363
420
|
when 'show', 'new', 'update'
|
364
421
|
hm_stuff << if hm_fk_name
|
365
|
-
if hm_assoc.klass.column_names.include?(hm_fk_name)
|
422
|
+
if hm_assoc.klass.column_names.include?(hm_fk_name) ||
|
423
|
+
(hm_fk_name.is_a?(String) && hm_fk_name.include?('.')) # HMT? (Could do a better check for this)
|
366
424
|
predicates = path_keys(hm_assoc, hm_fk_name, pk).map do |k, v|
|
367
|
-
v
|
425
|
+
if v == '[sti_type]'
|
426
|
+
"'#{k}': @#{obj_name}.#{hm_assoc.active_record.inheritance_column}"
|
427
|
+
else
|
428
|
+
v.is_a?(String) ? "'#{k}': '#{v}'" : "'#{k}': @#{obj_name}.#{v}"
|
429
|
+
end
|
368
430
|
end.join(', ')
|
369
431
|
"<%= link_to '#{assoc_name}', #{hm_assoc.klass._brick_index}_path({ #{predicates} }) %>\n"
|
370
432
|
else
|
@@ -402,6 +464,12 @@ function linkSchemas() {
|
|
402
464
|
table_options << "<option value=\"#{prefix}brick_orphans\">(Orphans)</option>".html_safe if is_orphans
|
403
465
|
table_options << "<option value=\"#{prefix}brick_orphans\">(Crosstab)</option>".html_safe if is_crosstab
|
404
466
|
css = +"<style>
|
467
|
+
#titleBox {
|
468
|
+
position: sticky;
|
469
|
+
display: inline-block;
|
470
|
+
left: 0;
|
471
|
+
}
|
472
|
+
|
405
473
|
h1, h3 {
|
406
474
|
margin-bottom: 0;
|
407
475
|
}
|
@@ -413,7 +481,6 @@ h1, h3 {
|
|
413
481
|
cursor: pointer;
|
414
482
|
}
|
415
483
|
#mermaidErd {
|
416
|
-
position: relative;
|
417
484
|
display: none;
|
418
485
|
}
|
419
486
|
#mermaidErd .exclude {
|
@@ -622,13 +689,24 @@ def hide_bcrypt(val, max_len = 200)
|
|
622
689
|
end
|
623
690
|
end
|
624
691
|
def display_value(col_type, val)
|
692
|
+
is_mssql_geography = nil
|
693
|
+
# Some binary thing that really looks like a Microsoft-encoded WGS84 point? (With the first two bytes, E6 10, indicating an EPSG code of 4326)
|
694
|
+
if col_type == :binary && val && val.length < 31 && (val.length - 6) % 8 == 0 && val[0..5].bytes == [230, 16, 0, 0, 1, 12]
|
695
|
+
col_type = 'geography'
|
696
|
+
is_mssql_geography = true
|
697
|
+
end
|
625
698
|
case col_type
|
626
699
|
when 'geometry', 'geography'
|
627
700
|
if Object.const_defined?('RGeo')
|
628
701
|
@is_mysql = ['Mysql2', 'Trilogy'].include?(ActiveRecord::Base.connection.adapter_name) if @is_mysql.nil?
|
629
702
|
@is_mssql = ActiveRecord::Base.connection.adapter_name == 'SQLServer' if @is_mssql.nil?
|
630
703
|
val_err = nil
|
631
|
-
|
704
|
+
|
705
|
+
if @is_mysql || (is_mssql_geography ||=
|
706
|
+
(@is_mssql ||
|
707
|
+
(val && val.length < 31 && (val.length - 6) % 8 == 0 && val[0..5].bytes == [230, 16, 0, 0, 1, 12])
|
708
|
+
)
|
709
|
+
)
|
632
710
|
# MySQL's \"Internal Geometry Format\" and MSSQL's Geography are like WKB, but with an initial 4 bytes that indicates the SRID.
|
633
711
|
if (srid = val&.[](0..3)&.unpack('I'))
|
634
712
|
val = val.dup.force_encoding('BINARY')[4..-1].bytes
|
@@ -642,20 +720,25 @@ def display_value(col_type, val)
|
|
642
720
|
# xx1x xxxx = IsWholeGlobe
|
643
721
|
# Convert Microsoft's unique geography binary to standard WKB
|
644
722
|
# (MSSQL point usually has two doubles, lng / lat, and can also have Z)
|
645
|
-
if
|
723
|
+
if is_mssql_geography
|
646
724
|
if val[0] == 1 && (val[1] & 8 > 0) && # Single point?
|
647
|
-
|
648
|
-
|
649
|
-
new_val = [0, 0, 0, 0, 1]
|
650
|
-
new_val.concat(val[idx - 8...idx].reverse) while (idx += 8) <= val.length
|
651
|
-
val = new_val
|
725
|
+
(val.length - 2) % 8 == 0 && val.length < 27 # And containing up to three 8-byte values?
|
726
|
+
val = [0, 0, 0, 0, 1] + val[2..-1].reverse
|
652
727
|
else
|
653
728
|
val_err = '(Microsoft internal SQL geography type)'
|
654
729
|
end
|
655
730
|
end
|
656
731
|
end
|
657
732
|
end
|
658
|
-
val_err ||
|
733
|
+
unless val_err || val.nil?
|
734
|
+
if (geometry = RGeo::WKRep::WKBParser.new.parse(val.pack('c*'))).is_a?(RGeo::Cartesian::PointImpl) &&
|
735
|
+
!(geometry.y == 0.0 && geometry.x == 0.0)
|
736
|
+
# Create a POINT link to this style of Google maps URL: https://www.google.com/maps/place/38.7071296+-121.2810649/@38.7071296,-121.2810649,12z
|
737
|
+
geometry = \"<a href=\\\"https://www.google.com/maps/place/#\{geometry.y}+#\{geometry.x}/@#\{geometry.y},#\{geometry.x},12z\\\" target=\\\"blank\\\">#\{geometry.to_s}</a>\"
|
738
|
+
end
|
739
|
+
val = geometry
|
740
|
+
end
|
741
|
+
val_err || val
|
659
742
|
else
|
660
743
|
'(Add RGeo gem to parse geometry detail)'
|
661
744
|
end
|
@@ -671,13 +754,13 @@ def display_value(col_type, val)
|
|
671
754
|
end
|
672
755
|
|
673
756
|
def image_signatures
|
674
|
-
@image_signatures ||= { \"\\xFF\\xD8\\xFF\\xEE\" => 'jpeg',
|
675
|
-
\"\\xFF\\xD8\\xFF\\xE0\\x00\\x10\\x4A\\x46\\x49\\x46\\x00\\x01\" => 'jpeg',
|
676
|
-
\"\\x89PNG\\r\\n\\x1A\\n\" => 'png',
|
757
|
+
@image_signatures ||= { \"\\xFF\\xD8\\xFF\\xEE\".force_encoding('ASCII-8BIT') => 'jpeg',
|
758
|
+
\"\\xFF\\xD8\\xFF\\xE0\\x00\\x10\\x4A\\x46\\x49\\x46\\x00\\x01\".force_encoding('ASCII-8BIT') => 'jpeg',
|
759
|
+
\"\\x89PNG\\r\\n\\x1A\\n\".force_encoding('ASCII-8BIT') => 'png',
|
677
760
|
'<svg' => 'svg+xml', # %%% Not yet very good detection for SVG
|
678
|
-
'BM' => 'bmp',
|
679
|
-
'GIF87a' => 'gif',
|
680
|
-
'GIF89a' => 'gif' }
|
761
|
+
'BM'.force_encoding('ASCII-8BIT') => 'bmp',
|
762
|
+
'GIF87a'.force_encoding('ASCII-8BIT') => 'gif',
|
763
|
+
'GIF89a'.force_encoding('ASCII-8BIT') => 'gif' }
|
681
764
|
end
|
682
765
|
def display_binary(val)
|
683
766
|
if val[0..1] == \"\\x15\\x1C\" # One of those goofy Microsoft OLE containers?
|
@@ -741,56 +824,8 @@ callbacks = {} %>
|
|
741
824
|
|
742
825
|
# %%% When doing schema select, if we're on a new page go to index
|
743
826
|
script = "<script>
|
744
|
-
var schemaSelect = document.getElementById(\"schema\");
|
745
|
-
var tblSelect = document.getElementById(\"tbl\");
|
746
|
-
var brickSchema;
|
747
827
|
var #{table_name}HtColumns;
|
748
828
|
|
749
|
-
// This PageTransitionEvent fires when the page first loads, as well as after any other history
|
750
|
-
// transition such as when using the browser's Back and Forward buttons.
|
751
|
-
window.addEventListener(\"pageshow\", function() {
|
752
|
-
if (tblSelect) { // Always present
|
753
|
-
var i = #{::Brick.config.path_prefix ? '0' : 'schemaSelect ? 1 : 0'},
|
754
|
-
changeoutList = changeout(location.href);
|
755
|
-
for (; i < changeoutList.length; ++i) {
|
756
|
-
tblSelect.value = changeoutList[i];
|
757
|
-
if (tblSelect.value !== \"\") break;
|
758
|
-
}
|
759
|
-
|
760
|
-
tblSelect.addEventListener(\"change\", function () {
|
761
|
-
var lhr = changeout(location.href, null, this.value);
|
762
|
-
if (brickSchema)
|
763
|
-
lhr = changeout(lhr, \"_brick_schema\", schemaSelect.value);
|
764
|
-
location.href = lhr;
|
765
|
-
});
|
766
|
-
}
|
767
|
-
|
768
|
-
if (schemaSelect && schemaSelect.options.length > 1) { // First drop-down is only present if multitenant
|
769
|
-
brickSchema = changeout(location.href, \"_brick_schema\");
|
770
|
-
if (brickSchema) {
|
771
|
-
[... document.getElementsByTagName(\"A\")].forEach(function (a) { a.href = changeout(a.href, \"_brick_schema\", brickSchema); });
|
772
|
-
}
|
773
|
-
schemaSelect.value = brickSchema || \"public\";
|
774
|
-
schemaSelect.focus();
|
775
|
-
schemaSelect.addEventListener(\"change\", function () {
|
776
|
-
// If there's an ID then remove it (trim after selected table)
|
777
|
-
location.href = changeout(location.href, \"_brick_schema\", this.value, tblSelect.value);
|
778
|
-
});
|
779
|
-
}
|
780
|
-
|
781
|
-
[... document.getElementsByTagName(\"FORM\")].forEach(function (form) {
|
782
|
-
if (brickSchema)
|
783
|
-
form.action = changeout(form.action, \"_brick_schema\", brickSchema);
|
784
|
-
form.addEventListener('submit', function (ev) {
|
785
|
-
[... ev.target.getElementsByTagName(\"SELECT\")].forEach(function (select) {
|
786
|
-
if (select.value === \"^^^brick_NULL^^^\")
|
787
|
-
select.value = null;
|
788
|
-
});
|
789
|
-
return true;
|
790
|
-
});
|
791
|
-
});
|
792
|
-
});
|
793
|
-
|
794
829
|
// Add \"Are you sure?\" behaviour to any data-confirm buttons out there
|
795
830
|
document.querySelectorAll(\"input[type=submit][data-confirm]\").forEach(function (btn) {
|
796
831
|
btn.addEventListener(\"click\", function (evt) {
|
@@ -1092,13 +1127,16 @@ erDiagram
|
|
1092
1127
|
%></title>
|
1093
1128
|
</head>
|
1094
1129
|
<body>
|
1130
|
+
<div id=\"titleBox\">
|
1095
1131
|
<p style=\"color: green\"><%= notice %></p>#{"
|
1096
1132
|
#{schema_options}" if schema_options}
|
1097
1133
|
<select id=\"tbl\">#{table_options}</select>
|
1098
1134
|
<table id=\"resourceName\"><tr>
|
1099
|
-
<td><h1><%=
|
1135
|
+
<td><h1><%= td_count = 2
|
1136
|
+
model.name %></h1></td>
|
1100
1137
|
<td id=\"imgErd\" title=\"Show ERD\"></td>
|
1101
|
-
<% if Object.const_defined?('Avo') && ::Avo.respond_to?(:railtie_namespace)
|
1138
|
+
<% if Object.const_defined?('Avo') && ::Avo.respond_to?(:railtie_namespace)
|
1139
|
+
td_count += 1 %>
|
1102
1140
|
<td><%= link_to_brick(
|
1103
1141
|
avo_svg,
|
1104
1142
|
{ index_proc: Proc.new do |avo_model|
|
@@ -1107,7 +1145,9 @@ erDiagram
|
|
1107
1145
|
title: \"#\{model.name} in Avo\" }
|
1108
1146
|
) %></td>
|
1109
1147
|
<% end %>
|
1110
|
-
</tr
|
1148
|
+
</tr><%= if (page_num = @#{table_name}._brick_page_num)
|
1149
|
+
\"<tr><td colspan=\\\"#\{td_count}\\\">Page #\{page_num}</td></tr>\".html_safe
|
1150
|
+
end %></table>#{template_link}<%
|
1111
1151
|
if description.present? %><%=
|
1112
1152
|
description %><br><%
|
1113
1153
|
end
|
@@ -1118,8 +1158,11 @@ erDiagram
|
|
1118
1158
|
id = id.first if id.is_a?(Array) && id.length == 1
|
1119
1159
|
origin = (key_parts = k.split('.')).length == 1 ? model : model.reflect_on_association(key_parts.first).klass
|
1120
1160
|
if (destination_fk = Brick.relations[origin.table_name][:fks].values.find { |fk| fk[:fk] == key_parts.last }) &&
|
1121
|
-
(
|
1122
|
-
|
1161
|
+
(objs = (destination = origin.reflect_on_association(destination_fk[:assoc_name])&.klass)&.find(id))
|
1162
|
+
objs = [objs] unless objs.is_a?(Array) %>
|
1163
|
+
<h3>for <% objs.each do |obj| %><%=
|
1164
|
+
link_to \"#{"#\{obj.brick_descrip\} (#\{destination.name\})\""}, send(\"#\{destination._brick_index(:singular)\}_path\".to_sym, id)
|
1165
|
+
%><% end %></h3><%
|
1123
1166
|
end
|
1124
1167
|
end %>
|
1125
1168
|
(<%= link_to \"See all #\{model.base_class.name.split('::').last.pluralize}\", #{@_brick_model._brick_index}_path %>)
|
@@ -1139,6 +1182,7 @@ erDiagram
|
|
1139
1182
|
});
|
1140
1183
|
</script>
|
1141
1184
|
<% end %>
|
1185
|
+
</div>
|
1142
1186
|
#{erd_markup}
|
1143
1187
|
|
1144
1188
|
<%= # Consider getting the name from the association -- hm.first.name -- if a more \"friendly\" alias should be used for a screwy table name
|
@@ -1263,7 +1307,9 @@ erDiagram
|
|
1263
1307
|
<head>
|
1264
1308
|
#{css}
|
1265
1309
|
<title><%=
|
1266
|
-
|
1310
|
+
model = (obj = @#{obj_name})&.class
|
1311
|
+
model_name = @#{obj_name}.#{inh_col = @_brick_model.inheritance_column} if obj.respond_to?(:#{inh_col})
|
1312
|
+
page_title = (\"#\{model_name ||= model.name}: #\{obj&.brick_descrip || controller_name}\")
|
1267
1313
|
%></title>
|
1268
1314
|
</head>
|
1269
1315
|
<body>
|
@@ -1297,12 +1343,12 @@ end
|
|
1297
1343
|
<% if obj
|
1298
1344
|
# path_options = [obj.#{pk}]
|
1299
1345
|
# path_options << { '_brick_schema': } if
|
1300
|
-
# url = send(:#\{
|
1346
|
+
# url = send(:#\{model._brick_index(:singular)}_path, obj.#{pk})
|
1301
1347
|
options = {}
|
1302
1348
|
options[:url] = send(\"#\{#{model_name}._brick_index(:singular)}_path\".to_sym, obj) if ::Brick.config.path_prefix
|
1303
1349
|
%>
|
1304
1350
|
<br><br>
|
1305
|
-
|
1351
|
+
<%= form_for(obj.becomes(#{model_name}), options) do |f| %>
|
1306
1352
|
<table class=\"shadow\">
|
1307
1353
|
<% has_fields = false
|
1308
1354
|
@#{obj_name}.attributes.each do |k, val|
|
@@ -1393,11 +1439,21 @@ end
|
|
1393
1439
|
# In Postgres labels of data stored in a hierarchical tree-like structure
|
1394
1440
|
# If it's not yet enabled then: create extension ltree;
|
1395
1441
|
val %>
|
1396
|
-
<% when :binary
|
1442
|
+
<% when :binary %>
|
1443
|
+
<%= is_revert = false
|
1444
|
+
if val
|
1445
|
+
# %%% This same kind of geography check is done two other times above ... would be great to DRY it up.
|
1446
|
+
if val.length < 31 && (val.length - 6) % 8 == 0 && val[0..5].bytes == [230, 16, 0, 0, 1, 12]
|
1447
|
+
display_value('geography', val)
|
1448
|
+
else
|
1449
|
+
display_binary(val)
|
1450
|
+
end.html_safe
|
1451
|
+
end %>
|
1452
|
+
<% when :primary_key
|
1397
1453
|
is_revert = false %>
|
1398
1454
|
<% else %>
|
1399
1455
|
<%= is_revert = false
|
1400
|
-
display_value(col_type, val) %>
|
1456
|
+
display_value(col_type, val).html_safe %>
|
1401
1457
|
<% end
|
1402
1458
|
end
|
1403
1459
|
if is_revert
|
@@ -1414,11 +1470,11 @@ end
|
|
1414
1470
|
<tr><td colspan=\"2\">(No displayable fields)</td></tr>
|
1415
1471
|
<% end %>
|
1416
1472
|
</table>
|
1417
|
-
<%
|
1473
|
+
<% end %>
|
1418
1474
|
|
1419
1475
|
#{unless args.first == 'new'
|
1420
|
-
# Was: confirm_are_you_sure = ActionView.version < ::Gem::Version.new('7.0') ? "data: { confirm: 'Delete
|
1421
|
-
confirm_are_you_sure = "data: { confirm: 'Delete
|
1476
|
+
# Was: confirm_are_you_sure = ActionView.version < ::Gem::Version.new('7.0') ? "data: { confirm: 'Delete #\{model_name} -- Are you sure?' }" : "form: { data: { turbo_confirm: 'Delete #\{model_name} -- Are you sure?' } }"
|
1477
|
+
confirm_are_you_sure = "data: { confirm: 'Delete #\{model_name} -- Are you sure?' }"
|
1422
1478
|
hms_headers.each_with_object(+'') do |hm, s|
|
1423
1479
|
# %%% Would be able to remove this when multiple foreign keys to same destination becomes bulletproof
|
1424
1480
|
next if hm.first.options[:through] && !hm.first.through_reflection
|
@@ -1426,11 +1482,24 @@ end
|
|
1426
1482
|
if (pk = hm.first.klass.primary_key)
|
1427
1483
|
hm_singular_name = (hm_name = hm.first.name.to_s).singularize.underscore
|
1428
1484
|
obj_pk = (pk.is_a?(Array) ? pk : [pk]).each_with_object([]) { |pk_part, s| s << "#{hm_singular_name}.#{pk_part}" }.join(', ')
|
1485
|
+
poly_fix = if (poly_type = (hm.first.options[:as] && hm.first.type))
|
1486
|
+
"
|
1487
|
+
# Let's fix an unexpected \"feature\" of AR -- when going through a polymorphic has_many
|
1488
|
+
# association that points to an STI model then filtering for the __able_type column is done
|
1489
|
+
# with a .where(). And the polymorphic class name it points to is the base class name of
|
1490
|
+
# the STI model instead of its subclass.
|
1491
|
+
if (poly_type = #{poly_type.inspect}) &&
|
1492
|
+
@#{obj_name}.respond_to?(:#{@_brick_model.inheritance_column}) &&
|
1493
|
+
(base_type = collection.where_values_hash[poly_type])
|
1494
|
+
collection = collection.rewhere(poly_type => [base_type, @#{obj_name}.#{@_brick_model.inheritance_column}])
|
1495
|
+
end"
|
1496
|
+
end
|
1429
1497
|
s << "<table id=\"#{hm_name}\" class=\"shadow\">
|
1430
|
-
<tr><th>#{hm[3]}</th></tr>
|
1498
|
+
<tr><th>#{hm[1]}#{' poly' if hm[0].options[:as]} #{hm[3]}</th></tr>
|
1431
1499
|
<% collection = @#{obj_name}.#{hm_name}
|
1432
1500
|
collection = case collection
|
1433
|
-
when ActiveRecord::Associations::CollectionProxy
|
1501
|
+
when ActiveRecord::Associations::CollectionProxy#{
|
1502
|
+
poly_fix}
|
1434
1503
|
collection.order(#{pk.inspect})
|
1435
1504
|
when ActiveRecord::Base # Object from a has_one
|
1436
1505
|
[collection]
|
@@ -1490,7 +1559,7 @@ flatpickr(\".timepicker\", {enableTime: true, noCalendar: true});
|
|
1490
1559
|
if (imgErd) imgErd.addEventListener(\"click\", showErd);
|
1491
1560
|
function showErd() {
|
1492
1561
|
imgErd.style.display = \"none\";
|
1493
|
-
mermaidErd.style.display = \"
|
1562
|
+
mermaidErd.style.display = \"block\";
|
1494
1563
|
if (mermaidCode) return; // Cut it short if we've already rendered the diagram
|
1495
1564
|
|
1496
1565
|
mermaidCode = document.createElement(\"SCRIPT\");
|
@@ -56,85 +56,85 @@ module Brick::Rails::FormTags
|
|
56
56
|
end
|
57
57
|
out << "</tr></thead>
|
58
58
|
<tbody>"
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
else
|
102
|
-
hm_klass = (col = cols[col_name])[1]
|
103
|
-
if col[2] == 'HO'
|
104
|
-
descrips = bt_descrip[col_name.to_sym][hm_klass]
|
105
|
-
if (ho_id = (ho_id_col = descrips.last).map { |id_col| obj.send(id_col.to_sym) })&.first
|
106
|
-
ho_txt = hm_klass.brick_descrip(obj, descrips[0..-2].map { |id| obj.send(id.last[0..62]) }, ho_id_col)
|
107
|
-
out << link_to(ho_txt, send("#{hm_klass.base_class._brick_index(:singular)}_path".to_sym, ho_id))
|
108
|
-
end
|
59
|
+
# %%% Have once gotten this error with MSSQL referring to http://localhost:3000/warehouse/cold_room_temperatures__archive
|
60
|
+
# ActiveRecord::StatementTimeout in Warehouse::ColdRoomTemperatures_Archive#index
|
61
|
+
# TinyTds::Error: Adaptive Server connection timed out
|
62
|
+
# (After restarting the server it worked fine again.)
|
63
|
+
relation.each do |obj|
|
64
|
+
out << "<tr>\n"
|
65
|
+
out << "<td>#{link_to('⇛', send("#{klass._brick_index(:singular)}_path".to_sym,
|
66
|
+
pk.map { |pk_part| obj.send(pk_part.to_sym) }), { class: 'big-arrow' })}</td>\n" if pk.present?
|
67
|
+
sequence.each do |col_name|
|
68
|
+
val = obj.attributes[col_name]
|
69
|
+
out << '<td'
|
70
|
+
out << ' class=\"dimmed\"' unless cols.key?(col_name) || (cust_col = cust_cols[col_name]) ||
|
71
|
+
(col_name.is_a?(Symbol) && bts.key?(col_name)) # HOT
|
72
|
+
out << '>'
|
73
|
+
if (bt = bts[col_name])
|
74
|
+
if bt[2] # Polymorphic?
|
75
|
+
bt_class = obj.send("#{bt.first}_type")
|
76
|
+
base_class_underscored = (::Brick.existing_stis[bt_class] || bt_class).constantize.base_class._brick_index(:singular)
|
77
|
+
poly_id = obj.send("#{bt.first}_id")
|
78
|
+
out << link_to("#{bt_class} ##{poly_id}", send("#{base_class_underscored}_path".to_sym, poly_id)) if poly_id
|
79
|
+
else # BT or HOT
|
80
|
+
bt_class = bt[1].first.first
|
81
|
+
descrips = bt_descrip[bt.first][bt_class]
|
82
|
+
bt_id_col = if descrips.nil?
|
83
|
+
puts "Caught it in the act for obj / #{col_name}!"
|
84
|
+
elsif descrips.length == 1
|
85
|
+
[obj.class.reflect_on_association(bt.first)&.foreign_key]
|
86
|
+
else
|
87
|
+
descrips.last
|
88
|
+
end
|
89
|
+
bt_txt = bt_class.brick_descrip(
|
90
|
+
# 0..62 because Postgres column names are limited to 63 characters
|
91
|
+
obj, descrips[0..-2].map { |id| obj.send(id.last[0..62]) }, bt_id_col
|
92
|
+
)
|
93
|
+
bt_txt = display_binary(bt_txt).html_safe if bt_txt&.encoding&.name == 'ASCII-8BIT'
|
94
|
+
bt_txt ||= "<span class=\"orphan\"><< Orphaned ID: #{val} >></span>" if val
|
95
|
+
bt_id = bt_id_col&.map { |id_col| obj.respond_to?(id_sym = id_col.to_sym) ? obj.send(id_sym) : id_col }
|
96
|
+
out << (bt_id&.first ? link_to(bt_txt, send("#{bt_class.base_class._brick_index(:singular)}_path".to_sym, bt_id)) : bt_txt || '')
|
97
|
+
end
|
98
|
+
elsif (hms_col = hms_cols[col_name])
|
99
|
+
if hms_col.length == 1
|
100
|
+
out << hms_col.first
|
109
101
|
else
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
102
|
+
hm_klass = (col = cols[col_name])[1]
|
103
|
+
if col[2] == 'HO'
|
104
|
+
descrips = bt_descrip[col_name.to_sym][hm_klass]
|
105
|
+
if (ho_id = (ho_id_col = descrips.last).map { |id_col| obj.send(id_col.to_sym) })&.first
|
106
|
+
ho_txt = hm_klass.brick_descrip(obj, descrips[0..-2].map { |id| obj.send(id.last[0..62]) }, ho_id_col)
|
107
|
+
out << link_to(ho_txt, send("#{hm_klass.base_class._brick_index(:singular)}_path".to_sym, ho_id))
|
108
|
+
end
|
109
|
+
else
|
110
|
+
if (ct = obj.send(hms_col[1].to_sym)&.to_i)&.positive?
|
111
|
+
out << "#{link_to("#{ct || 'View'} #{hms_col.first}",
|
112
|
+
send("#{hm_klass._brick_index}_path".to_sym,
|
113
|
+
hms_col[2].each_with_object({}) { |v, s| s[v.first] = v.last.is_a?(String) ? v.last : obj.send(v.last) })
|
114
|
+
)}\n"
|
115
|
+
end
|
115
116
|
end
|
116
117
|
end
|
118
|
+
elsif (col = cols[col_name]).is_a?(ActiveRecord::ConnectionAdapters::Column)
|
119
|
+
binding.pry if col.is_a?(Array)
|
120
|
+
col_type = col&.sql_type == 'geography' ? col.sql_type : col&.type
|
121
|
+
out << display_value(col_type || col&.sql_type, val).to_s
|
122
|
+
elsif cust_col
|
123
|
+
data = cust_col.first.map { |cc_part| obj.send(cc_part.last) }
|
124
|
+
cust_txt = klass.brick_descrip(cust_col[-2], data)
|
125
|
+
if (link_id = obj.send(cust_col.last[1]) if cust_col.last)
|
126
|
+
out << link_to(cust_txt, send("#{cust_col.last.first._brick_index(:singular)}_path", link_id))
|
127
|
+
else
|
128
|
+
out << (cust_txt || '')
|
129
|
+
end
|
130
|
+
else # Bad column name!
|
131
|
+
out << '?'
|
117
132
|
end
|
118
|
-
|
119
|
-
binding.pry if col.is_a?(Array)
|
120
|
-
col_type = col&.sql_type == 'geography' ? col.sql_type : col&.type
|
121
|
-
out << display_value(col_type || col&.sql_type, val).to_s
|
122
|
-
elsif cust_col
|
123
|
-
data = cust_col.first.map { |cc_part| obj.send(cc_part.last) }
|
124
|
-
cust_txt = klass.brick_descrip(cust_col[-2], data)
|
125
|
-
if (link_id = obj.send(cust_col.last[1]) if cust_col.last)
|
126
|
-
out << link_to(cust_txt, send("#{cust_col.last.first._brick_index(:singular)}_path", link_id))
|
127
|
-
else
|
128
|
-
out << (cust_txt || '')
|
129
|
-
end
|
130
|
-
else # Bad column name!
|
131
|
-
out << '?'
|
133
|
+
out << '</td>'
|
132
134
|
end
|
133
|
-
out << '</
|
135
|
+
out << '</tr>'
|
134
136
|
end
|
135
|
-
|
136
|
-
end
|
137
|
-
out << " </tbody>
|
137
|
+
out << " </tbody>
|
138
138
|
</table>
|
139
139
|
"
|
140
140
|
out.html_safe
|
@@ -143,6 +143,16 @@ module Brick::Rails::FormTags
|
|
143
143
|
def link_to_brick(*args, **kwargs)
|
144
144
|
return unless ::Brick.config.mode == :on
|
145
145
|
|
146
|
+
kwargs.merge!(args.pop) if args.last.is_a?(Hash)
|
147
|
+
# Avoid infinite recursion
|
148
|
+
if (visited = kwargs.fetch(:visited, nil))
|
149
|
+
return if visited.key?(object_id)
|
150
|
+
|
151
|
+
kwargs[:visited][object_id] = nil
|
152
|
+
else
|
153
|
+
kwargs[:visited] = {}
|
154
|
+
end
|
155
|
+
|
146
156
|
text = ((args.first.is_a?(String) || args.first.is_a?(Proc)) && args.shift) || args[1]
|
147
157
|
text = text.call if text.is_a?(Proc)
|
148
158
|
klass_or_obj = ((args.first.is_a?(ActiveRecord::Relation) ||
|
@@ -192,13 +202,14 @@ module Brick::Rails::FormTags
|
|
192
202
|
app_routes = Rails.application.routes # In case we're operating in another engine, reference the application since Brick routes are placed there.
|
193
203
|
if (klass_or_obj&.is_a?(Class) && klass_or_obj < ActiveRecord::Base) ||
|
194
204
|
(klass_or_obj&.is_a?(ActiveRecord::Base) && klass_or_obj.new_record? && (klass_or_obj = klass_or_obj.class))
|
195
|
-
path = (proc = kwargs[:index_proc]) ? proc.call(klass_or_obj) : "#{app_routes.path_for(controller: klass_or_obj.base_class._brick_index, action: :index)}#{filter}"
|
205
|
+
path = (proc = kwargs[:index_proc]) ? proc.call(klass_or_obj) : "#{app_routes.path_for(controller: klass_or_obj.base_class._brick_index(nil, '/'), action: :index)}#{filter}"
|
196
206
|
lt_args = [text || "Index for #{klass_or_obj.name.pluralize}", path]
|
197
207
|
else
|
198
208
|
# If there are multiple incoming parameters then last one is probably the actual ID, and first few might be some nested tree of stuff leading up to it
|
199
|
-
path = (proc = kwargs[:show_proc]) ? proc.call(klass_or_obj) : "#{app_routes.path_for(controller: klass_or_obj.class.base_class._brick_index, action: :show, id: klass_or_obj)}#{filter}"
|
209
|
+
path = (proc = kwargs[:show_proc]) ? proc.call(klass_or_obj) : "#{app_routes.path_for(controller: klass_or_obj.class.base_class._brick_index(nil, '/'), action: :show, id: klass_or_obj)}#{filter}"
|
200
210
|
lt_args = [text || "Show this #{klass_or_obj.class.name}", path]
|
201
211
|
end
|
212
|
+
kwargs.delete(:visited)
|
202
213
|
link_to(*lt_args, **kwargs)
|
203
214
|
else
|
204
215
|
# puts "Warning: link_to_brick could not find a class for \"#{controller_path}\" -- consider setting @_brick_model within that controller."
|
@@ -215,7 +226,7 @@ module Brick::Rails::FormTags
|
|
215
226
|
if links.length == 1 # If there's only one match then use any text that was supplied
|
216
227
|
link_to_brick(text || links.first.last.join('/'), links.first.first, **kwargs)
|
217
228
|
else
|
218
|
-
links.
|
229
|
+
links.each_with_object([]) { |v, s| s << link if link = link_to_brick(v.join('/'), v, **kwargs) }.join(' ').html_safe
|
219
230
|
end
|
220
231
|
end
|
221
232
|
end # link_to_brick
|
data/lib/brick/version_number.rb
CHANGED
@@ -288,16 +288,18 @@ if ActiveRecord::Base.respond_to?(:brick_select)
|
|
288
288
|
|
289
289
|
# # POLYMORPHIC ASSOCIATIONS
|
290
290
|
|
291
|
-
# #
|
292
|
-
|
291
|
+
# # Polymorphic associations are set up by providing a model name and polymorphic association name#{poly}
|
292
|
+
|
293
|
+
# # For multi-tenant databases that use a separate schema for each tenant, a single representative database schema
|
294
|
+
# # can be analysed to determine the range of polymorphic classes that can be used for each association. Hopefully
|
295
|
+
# # the schema chosen is one loaded with existing data that is representative of all possible polymorphic
|
296
|
+
# # associations.
|
293
297
|
# Brick.schema_behavior = :namespaced
|
294
298
|
#{Brick.config.schema_behavior.present? ? " Brick.schema_behavior = { multitenant: { schema_to_analyse: #{
|
295
299
|
Brick.config.schema_behavior[:multitenant]&.fetch(:schema_to_analyse, nil).inspect}" :
|
296
300
|
" # Brick.schema_behavior = { multitenant: { schema_to_analyse: 'engineering'"
|
297
301
|
} } }
|
298
302
|
|
299
|
-
# # Polymorphic associations are set up by providing a model name and polymorphic association name#{poly}
|
300
|
-
|
301
303
|
# # DEFAULT ROOT ROUTE
|
302
304
|
|
303
305
|
# # If a default route is not supplied, Brick attempts to find the most \"central\" table and wires up the default
|
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.104
|
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-01-
|
11
|
+
date: 2023-01-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -164,20 +164,6 @@ dependencies:
|
|
164
164
|
- - "~>"
|
165
165
|
- !ruby/object:Gem::Version
|
166
166
|
version: 1.42.0
|
167
|
-
- !ruby/object:Gem::Dependency
|
168
|
-
name: mysql2
|
169
|
-
requirement: !ruby/object:Gem::Requirement
|
170
|
-
requirements:
|
171
|
-
- - "~>"
|
172
|
-
- !ruby/object:Gem::Version
|
173
|
-
version: '0.5'
|
174
|
-
type: :development
|
175
|
-
prerelease: false
|
176
|
-
version_requirements: !ruby/object:Gem::Requirement
|
177
|
-
requirements:
|
178
|
-
- - "~>"
|
179
|
-
- !ruby/object:Gem::Version
|
180
|
-
version: '0.5'
|
181
167
|
- !ruby/object:Gem::Dependency
|
182
168
|
name: pg
|
183
169
|
requirement: !ruby/object:Gem::Requirement
|