brick 1.0.101 → 1.0.103
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 +49 -35
- data/lib/brick/frameworks/rails/engine.rb +165 -82
- data/lib/brick/frameworks/rails/form_tags.rb +2 -1
- data/lib/brick/version_number.rb +1 -1
- data/lib/brick.rb +144 -8
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 74743982216a9827513b4aaa68fe0887c9ba3e7b78c45ff52f0a2f2b99dc7b88
|
4
|
+
data.tar.gz: 3857a95e891e7561d285dd3ecbdeb6c4c16cc9a8205e7b733b55867ed7a69f64
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8b71aa5b1d4da8c4aa1ce88af6d0767c12bdf72b2457594575795d4b9b3f36d1bfb2adef82413a3bc80e041813e7bc6c05768016c5e4cfc197e3bbb730113934
|
7
|
+
data.tar.gz: 6399e040cb4b54eac4d7a09b907cfba11037a4b3391dd3a86b4845e79bd0c4d4e169586c095fdaaaa8506f346628072c9c4c9b6d2ed60c3306a58866e6f9d030
|
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
|
@@ -119,30 +118,32 @@ module ActiveRecord
|
|
119
118
|
end
|
120
119
|
s << part_sym
|
121
120
|
end
|
122
|
-
if
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
if klass&.column_names.exclude?(parts.last) &&
|
131
|
-
(klass = (orig_class = klass).reflect_on_association(possible_dsl = parts.pop.to_sym)&.klass)
|
132
|
-
if prefix.empty? # Custom columns start with an empty prefix
|
133
|
-
prefix << parts.shift until parts.empty?
|
121
|
+
if first_parts
|
122
|
+
if (parts = prefix + first_parts + [parts[-1]]).length > 1 && klass
|
123
|
+
unless is_polymorphic
|
124
|
+
s = build_array
|
125
|
+
parts[0..-3].each { |v| s = s[v.to_sym] }
|
126
|
+
s[parts[-2]] = nil # unless parts[-2].empty? # Using []= will "hydrate" any missing part(s) in our whole series
|
127
|
+
end
|
128
|
+
translations[parts[0..-2].join('.')] = klass
|
134
129
|
end
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
130
|
+
if klass&.column_names.exclude?(parts.last) &&
|
131
|
+
(klass = (orig_class = klass).reflect_on_association(possible_dsl = parts.pop.to_sym)&.klass)
|
132
|
+
if prefix.empty? # Custom columns start with an empty prefix
|
133
|
+
prefix << parts.shift until parts.empty?
|
134
|
+
end
|
135
|
+
# Expand this entry which refers to an association name
|
136
|
+
members2, dsl2a = klass.brick_parse_dsl(build_array, prefix + [possible_dsl], translations, is_polymorphic, nil, true)
|
137
|
+
members += members2
|
138
|
+
dsl2 << dsl2a
|
139
|
+
dsl3 << dsl2a
|
140
|
+
else
|
141
|
+
dsl2 << "[#{bracket_name}]"
|
142
|
+
if emit_dsl
|
143
|
+
dsl3 << "[#{prefix[1..-1].map { |p| "#{p.to_s}." }.join if prefix.length > 1}#{bracket_name}]"
|
144
|
+
end
|
145
|
+
members << parts
|
144
146
|
end
|
145
|
-
members << parts
|
146
147
|
end
|
147
148
|
bracket_name = nil
|
148
149
|
else
|
@@ -409,7 +410,7 @@ module ActiveRecord
|
|
409
410
|
model._brick_calculate_bts_hms(translations, join_array) if is_add_bts || is_add_hms
|
410
411
|
|
411
412
|
is_postgres = ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
|
412
|
-
is_mysql = ActiveRecord::Base.connection.adapter_name
|
413
|
+
is_mysql = ['Mysql2', 'Trilogy'].include?(ActiveRecord::Base.connection.adapter_name)
|
413
414
|
is_mssql = ActiveRecord::Base.connection.adapter_name == 'SQLServer'
|
414
415
|
is_distinct = nil
|
415
416
|
wheres = {}
|
@@ -557,7 +558,7 @@ module ActiveRecord
|
|
557
558
|
brick_link = rel_dupe.brick_links[sel_col.first]
|
558
559
|
field_tbl_name = brick_link&.split('.')&.last ||
|
559
560
|
# ... so here's a best-effort guess for what the table name might be.
|
560
|
-
rel_dupe.klass.reflect_on_association(sel_col.first)
|
561
|
+
rel_dupe.klass.reflect_on_association(sel_col.first)&.klass&.table_name
|
561
562
|
# If it's Oracle, quote any AREL aliases that had been applied
|
562
563
|
field_tbl_name = "\"#{field_tbl_name}\"" if ::Brick.is_oracle && rel_dupe.brick_links.values.include?(field_tbl_name)
|
563
564
|
|
@@ -803,6 +804,7 @@ JOIN (SELECT #{hm_selects.map { |s| "#{'br_t0.' if from_clause}#{s}" }.join(', '
|
|
803
804
|
alias _brick_find_sti_class find_sti_class
|
804
805
|
def find_sti_class(type_name)
|
805
806
|
if ::Brick.sti_models.key?(type_name ||= name)
|
807
|
+
# Used to be: ::Brick.sti_models[type_name].fetch(:base, nil) || _brick_find_sti_class(type_name)
|
806
808
|
_brick_find_sti_class(type_name)
|
807
809
|
else
|
808
810
|
# This auto-STI is more of a brute-force approach, building modules where needed
|
@@ -1407,7 +1409,7 @@ class Object
|
|
1407
1409
|
singular_table_name = ActiveSupport::Inflector.singularize(ActiveSupport::Inflector.underscore(plural_class_name))
|
1408
1410
|
pk = model&._brick_primary_key(relations.fetch(table_name, nil))
|
1409
1411
|
is_postgres = ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
|
1410
|
-
is_mysql = ActiveRecord::Base.connection.adapter_name
|
1412
|
+
is_mysql = ['Mysql2', 'Trilogy'].include?(ActiveRecord::Base.connection.adapter_name)
|
1411
1413
|
|
1412
1414
|
code = +"class #{class_name} < #{controller_base&.name || 'ApplicationController'}\n"
|
1413
1415
|
built_controller = Class.new(controller_base || ActionController::Base) do |new_controller_class|
|
@@ -1622,6 +1624,18 @@ class Object
|
|
1622
1624
|
end
|
1623
1625
|
|
1624
1626
|
unless is_openapi || is_avo
|
1627
|
+
# Skip showing Bullet gem optimisation messages
|
1628
|
+
if Object.const_defined?('Bullet') && Bullet.respond_to?(:enable?)
|
1629
|
+
around_action :skip_bullet
|
1630
|
+
def skip_bullet
|
1631
|
+
bullet_enabled = Bullet.enable?
|
1632
|
+
Bullet.enable = false
|
1633
|
+
yield
|
1634
|
+
ensure
|
1635
|
+
Bullet.enable = bullet_enabled
|
1636
|
+
end
|
1637
|
+
end
|
1638
|
+
|
1625
1639
|
_, order_by_txt = model._brick_calculate_ordering(default_ordering(table_name, pk)) if pk
|
1626
1640
|
code << " def index\n"
|
1627
1641
|
code << " @#{table_name.pluralize} = #{model.name}#{pk&.present? ? ".order(#{order_by_txt.join(', ')})" : '.all'}\n"
|
@@ -1935,7 +1949,7 @@ end.class_exec do
|
|
1935
1949
|
puts "*** In the brick.rb initializer the line \"::Brick.schema_behavior = ...\" refers to schema(s) called #{possible_schemas.map { |s| "\"#{s}\"" }.join(', ')}. No mentioned schema exists. ***"
|
1936
1950
|
end
|
1937
1951
|
end
|
1938
|
-
when 'Mysql2'
|
1952
|
+
when 'Mysql2', 'Trilogy'
|
1939
1953
|
::Brick.default_schema = schema = ActiveRecord::Base.connection.current_database
|
1940
1954
|
when 'OracleEnhanced'
|
1941
1955
|
# ActiveRecord::Base.connection.current_database will be something like "XEPDB1"
|
@@ -2070,7 +2084,7 @@ ORDER BY 1, 2, c.internal_column_id, acc.position"
|
|
2070
2084
|
# end
|
2071
2085
|
# schema = ::Brick.default_schema # Reset back for this next round of fun
|
2072
2086
|
case ActiveRecord::Base.connection.adapter_name
|
2073
|
-
when 'PostgreSQL', 'Mysql2', 'SQLServer'
|
2087
|
+
when 'PostgreSQL', 'Mysql2', 'Trilogy', 'SQLServer'
|
2074
2088
|
sql = "SELECT kcu1.CONSTRAINT_SCHEMA, kcu1.TABLE_NAME, kcu1.COLUMN_NAME,
|
2075
2089
|
kcu2.CONSTRAINT_SCHEMA AS primary_schema, kcu2.TABLE_NAME AS primary_table, kcu1.CONSTRAINT_NAME AS CONSTRAINT_SCHEMA_FK
|
2076
2090
|
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS rc
|
@@ -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
|
@@ -288,7 +328,14 @@ function linkSchemas() {
|
|
288
328
|
else
|
289
329
|
[[fk_name, pk.length == 1 ? pk.first : pk.inspect]]
|
290
330
|
end
|
291
|
-
|
331
|
+
if hm_assoc.options.key?(:as)
|
332
|
+
poly_type = if hm_assoc.active_record.column_names.include?(hm_assoc.active_record.inheritance_column)
|
333
|
+
'[sti_type]'
|
334
|
+
else
|
335
|
+
hm_assoc.active_record.name
|
336
|
+
end
|
337
|
+
keys << [hm_assoc.inverse_of.foreign_type, poly_type]
|
338
|
+
end
|
292
339
|
keys.to_h
|
293
340
|
end
|
294
341
|
|
@@ -362,9 +409,14 @@ function linkSchemas() {
|
|
362
409
|
end
|
363
410
|
when 'show', 'new', 'update'
|
364
411
|
hm_stuff << if hm_fk_name
|
365
|
-
if hm_assoc.klass.column_names.include?(hm_fk_name)
|
412
|
+
if hm_assoc.klass.column_names.include?(hm_fk_name) ||
|
413
|
+
(hm_fk_name.is_a?(String) && hm_fk_name.include?('.')) # HMT? (Could do a better check for this)
|
366
414
|
predicates = path_keys(hm_assoc, hm_fk_name, pk).map do |k, v|
|
367
|
-
v
|
415
|
+
if v == '[sti_type]'
|
416
|
+
"'#{k}': @#{obj_name}.#{hm_assoc.active_record.inheritance_column}"
|
417
|
+
else
|
418
|
+
v.is_a?(String) ? "'#{k}': '#{v}'" : "'#{k}': @#{obj_name}.#{v}"
|
419
|
+
end
|
368
420
|
end.join(', ')
|
369
421
|
"<%= link_to '#{assoc_name}', #{hm_assoc.klass._brick_index}_path({ #{predicates} }) %>\n"
|
370
422
|
else
|
@@ -622,13 +674,24 @@ def hide_bcrypt(val, max_len = 200)
|
|
622
674
|
end
|
623
675
|
end
|
624
676
|
def display_value(col_type, val)
|
677
|
+
is_mssql_geography = nil
|
678
|
+
# 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)
|
679
|
+
if col_type == :binary && val && val.length < 31 && (val.length - 6) % 8 == 0 && val[0..5].bytes == [230, 16, 0, 0, 1, 12]
|
680
|
+
col_type = 'geography'
|
681
|
+
is_mssql_geography = true
|
682
|
+
end
|
625
683
|
case col_type
|
626
684
|
when 'geometry', 'geography'
|
627
685
|
if Object.const_defined?('RGeo')
|
628
|
-
@is_mysql = ActiveRecord::Base.connection.adapter_name
|
686
|
+
@is_mysql = ['Mysql2', 'Trilogy'].include?(ActiveRecord::Base.connection.adapter_name) if @is_mysql.nil?
|
629
687
|
@is_mssql = ActiveRecord::Base.connection.adapter_name == 'SQLServer' if @is_mssql.nil?
|
630
688
|
val_err = nil
|
631
|
-
|
689
|
+
|
690
|
+
if @is_mysql || (is_mssql_geography ||=
|
691
|
+
(@is_mssql ||
|
692
|
+
(val && val.length < 31 && (val.length - 6) % 8 == 0 && val[0..5].bytes == [230, 16, 0, 0, 1, 12])
|
693
|
+
)
|
694
|
+
)
|
632
695
|
# MySQL's \"Internal Geometry Format\" and MSSQL's Geography are like WKB, but with an initial 4 bytes that indicates the SRID.
|
633
696
|
if (srid = val&.[](0..3)&.unpack('I'))
|
634
697
|
val = val.dup.force_encoding('BINARY')[4..-1].bytes
|
@@ -642,23 +705,30 @@ def display_value(col_type, val)
|
|
642
705
|
# xx1x xxxx = IsWholeGlobe
|
643
706
|
# Convert Microsoft's unique geography binary to standard WKB
|
644
707
|
# (MSSQL point usually has two doubles, lng / lat, and can also have Z)
|
645
|
-
if
|
708
|
+
if is_mssql_geography
|
646
709
|
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
|
710
|
+
(val.length - 2) % 8 == 0 && val.length < 27 # And containing up to three 8-byte values?
|
711
|
+
val = [0, 0, 0, 0, 1] + val[2..-1].reverse
|
652
712
|
else
|
653
713
|
val_err = '(Microsoft internal SQL geography type)'
|
654
714
|
end
|
655
715
|
end
|
656
716
|
end
|
657
717
|
end
|
658
|
-
val_err ||
|
718
|
+
unless val_err || val.nil?
|
719
|
+
if (geometry = RGeo::WKRep::WKBParser.new.parse(val.pack('c*'))).is_a?(RGeo::Cartesian::PointImpl) &&
|
720
|
+
!(geometry.y == 0.0 && geometry.x == 0.0)
|
721
|
+
# 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
|
722
|
+
geometry = \"<a href=\\\"https://www.google.com/maps/place/#\{geometry.y}+#\{geometry.x}/@#\{geometry.y},#\{geometry.x},12z\\\" target=\\\"blank\\\">#\{geometry.to_s}</a>\"
|
723
|
+
end
|
724
|
+
val = geometry
|
725
|
+
end
|
726
|
+
val_err || val
|
659
727
|
else
|
660
728
|
'(Add RGeo gem to parse geometry detail)'
|
661
729
|
end
|
730
|
+
when :binary
|
731
|
+
display_binary(val) if val
|
662
732
|
else
|
663
733
|
if col_type
|
664
734
|
hide_bcrypt(val)
|
@@ -667,6 +737,40 @@ def display_value(col_type, val)
|
|
667
737
|
end
|
668
738
|
end
|
669
739
|
end
|
740
|
+
|
741
|
+
def image_signatures
|
742
|
+
@image_signatures ||= { \"\\xFF\\xD8\\xFF\\xEE\".force_encoding('ASCII-8BIT') => 'jpeg',
|
743
|
+
\"\\xFF\\xD8\\xFF\\xE0\\x00\\x10\\x4A\\x46\\x49\\x46\\x00\\x01\".force_encoding('ASCII-8BIT') => 'jpeg',
|
744
|
+
\"\\x89PNG\\r\\n\\x1A\\n\".force_encoding('ASCII-8BIT') => 'png',
|
745
|
+
'<svg' => 'svg+xml', # %%% Not yet very good detection for SVG
|
746
|
+
'BM'.force_encoding('ASCII-8BIT') => 'bmp',
|
747
|
+
'GIF87a'.force_encoding('ASCII-8BIT') => 'gif',
|
748
|
+
'GIF89a'.force_encoding('ASCII-8BIT') => 'gif' }
|
749
|
+
end
|
750
|
+
def display_binary(val)
|
751
|
+
if val[0..1] == \"\\x15\\x1C\" # One of those goofy Microsoft OLE containers?
|
752
|
+
package_header_length = val[2..3].bytes.reverse.inject(0) {|m, b| (m << 8) + b }
|
753
|
+
# This will often be just FF FF FF FF
|
754
|
+
# object_size = val[16..19].bytes.reverse.inject(0) {|m, b| (m << 8) + b }
|
755
|
+
friendly_and_class_names = val[20...package_header_length].split(\"\\0\")
|
756
|
+
object_type_name_length = val[package_header_length + 8..package_header_length+11].bytes.reverse.inject(0) {|m, b| (m << 8) + b }
|
757
|
+
friendly_and_class_names << val[package_header_length + 12...package_header_length + 12 + object_type_name_length].strip
|
758
|
+
# friendly_and_class_names will now be something like: ['Bitmap Image', 'Paint.Picture', 'PBrush']
|
759
|
+
real_object_size = val[package_header_length + 20 + object_type_name_length..package_header_length + 23 + object_type_name_length].bytes.reverse.inject(0) {|m, b| (m << 8) + b }
|
760
|
+
object_start = package_header_length + 24 + object_type_name_length
|
761
|
+
val = val[object_start...object_start + real_object_size]
|
762
|
+
end
|
763
|
+
if (signature = image_signatures.find { |k, _v| val[0...k.length] == k })
|
764
|
+
if val.length < 500_000
|
765
|
+
\"<img src=\\\"data:image/#\{signature.last};base64,#\{Base64.encode64(val)}\\\">\"
|
766
|
+
else
|
767
|
+
\"< #\{signature.last} image, #\{val.length} bytes >\"
|
768
|
+
end
|
769
|
+
else
|
770
|
+
\"< Binary, #\{val.length} bytes >\"
|
771
|
+
end
|
772
|
+
end
|
773
|
+
|
670
774
|
# Accommodate composite primary keys that include strings with forward-slash characters
|
671
775
|
def slashify(*vals)
|
672
776
|
vals.map { |val_part| val_part.is_a?(String) ? val_part.gsub('/', '^^sl^^') : val_part }
|
@@ -705,56 +809,8 @@ callbacks = {} %>
|
|
705
809
|
|
706
810
|
# %%% When doing schema select, if we're on a new page go to index
|
707
811
|
script = "<script>
|
708
|
-
var schemaSelect = document.getElementById(\"schema\");
|
709
|
-
var tblSelect = document.getElementById(\"tbl\");
|
710
|
-
var brickSchema;
|
711
812
|
var #{table_name}HtColumns;
|
712
813
|
|
713
|
-
// This PageTransitionEvent fires when the page first loads, as well as after any other history
|
714
|
-
// transition such as when using the browser's Back and Forward buttons.
|
715
|
-
window.addEventListener(\"pageshow\", function() {
|
716
|
-
if (tblSelect) { // Always present
|
717
|
-
var i = #{::Brick.config.path_prefix ? '0' : 'schemaSelect ? 1 : 0'},
|
718
|
-
changeoutList = changeout(location.href);
|
719
|
-
for (; i < changeoutList.length; ++i) {
|
720
|
-
tblSelect.value = changeoutList[i];
|
721
|
-
if (tblSelect.value !== \"\") break;
|
722
|
-
}
|
723
|
-
|
724
|
-
tblSelect.addEventListener(\"change\", function () {
|
725
|
-
var lhr = changeout(location.href, null, this.value);
|
726
|
-
if (brickSchema)
|
727
|
-
lhr = changeout(lhr, \"_brick_schema\", schemaSelect.value);
|
728
|
-
location.href = lhr;
|
729
|
-
});
|
730
|
-
}
|
731
|
-
|
732
|
-
if (schemaSelect && schemaSelect.options.length > 1) { // First drop-down is only present if multitenant
|
733
|
-
brickSchema = changeout(location.href, \"_brick_schema\");
|
734
|
-
if (brickSchema) {
|
735
|
-
[... document.getElementsByTagName(\"A\")].forEach(function (a) { a.href = changeout(a.href, \"_brick_schema\", brickSchema); });
|
736
|
-
}
|
737
|
-
schemaSelect.value = brickSchema || \"public\";
|
738
|
-
schemaSelect.focus();
|
739
|
-
schemaSelect.addEventListener(\"change\", function () {
|
740
|
-
// If there's an ID then remove it (trim after selected table)
|
741
|
-
location.href = changeout(location.href, \"_brick_schema\", this.value, tblSelect.value);
|
742
|
-
});
|
743
|
-
}
|
744
|
-
|
745
|
-
[... document.getElementsByTagName(\"FORM\")].forEach(function (form) {
|
746
|
-
if (brickSchema)
|
747
|
-
form.action = changeout(form.action, \"_brick_schema\", brickSchema);
|
748
|
-
form.addEventListener('submit', function (ev) {
|
749
|
-
[... ev.target.getElementsByTagName(\"SELECT\")].forEach(function (select) {
|
750
|
-
if (select.value === \"^^^brick_NULL^^^\")
|
751
|
-
select.value = null;
|
752
|
-
});
|
753
|
-
return true;
|
754
|
-
});
|
755
|
-
});
|
756
|
-
});
|
757
|
-
|
758
814
|
// Add \"Are you sure?\" behaviour to any data-confirm buttons out there
|
759
815
|
document.querySelectorAll(\"input[type=submit][data-confirm]\").forEach(function (btn) {
|
760
816
|
btn.addEventListener(\"click\", function (evt) {
|
@@ -1082,8 +1138,11 @@ erDiagram
|
|
1082
1138
|
id = id.first if id.is_a?(Array) && id.length == 1
|
1083
1139
|
origin = (key_parts = k.split('.')).length == 1 ? model : model.reflect_on_association(key_parts.first).klass
|
1084
1140
|
if (destination_fk = Brick.relations[origin.table_name][:fks].values.find { |fk| fk[:fk] == key_parts.last }) &&
|
1085
|
-
(
|
1086
|
-
|
1141
|
+
(objs = (destination = origin.reflect_on_association(destination_fk[:assoc_name])&.klass)&.find(id))
|
1142
|
+
objs = [objs] unless objs.is_a?(Array) %>
|
1143
|
+
<h3>for <% objs.each do |obj| %><%=
|
1144
|
+
link_to \"#{"#\{obj.brick_descrip\} (#\{destination.name\})\""}, send(\"#\{destination._brick_index(:singular)\}_path\".to_sym, id)
|
1145
|
+
%><% end %></h3><%
|
1087
1146
|
end
|
1088
1147
|
end %>
|
1089
1148
|
(<%= link_to \"See all #\{model.base_class.name.split('::').last.pluralize}\", #{@_brick_model._brick_index}_path %>)
|
@@ -1227,7 +1286,9 @@ erDiagram
|
|
1227
1286
|
<head>
|
1228
1287
|
#{css}
|
1229
1288
|
<title><%=
|
1230
|
-
|
1289
|
+
model = (obj = @#{obj_name})&.class
|
1290
|
+
model_name = @#{obj_name}.#{inh_col = @_brick_model.inheritance_column} if obj.respond_to?(:#{inh_col})
|
1291
|
+
page_title = (\"#\{model_name ||= model.name}: #\{obj&.brick_descrip || controller_name}\")
|
1231
1292
|
%></title>
|
1232
1293
|
</head>
|
1233
1294
|
<body>
|
@@ -1261,7 +1322,7 @@ end
|
|
1261
1322
|
<% if obj
|
1262
1323
|
# path_options = [obj.#{pk}]
|
1263
1324
|
# path_options << { '_brick_schema': } if
|
1264
|
-
# url = send(:#\{
|
1325
|
+
# url = send(:#\{model._brick_index(:singular)}_path, obj.#{pk})
|
1265
1326
|
options = {}
|
1266
1327
|
options[:url] = send(\"#\{#{model_name}._brick_index(:singular)}_path\".to_sym, obj) if ::Brick.config.path_prefix
|
1267
1328
|
%>
|
@@ -1357,7 +1418,17 @@ end
|
|
1357
1418
|
# In Postgres labels of data stored in a hierarchical tree-like structure
|
1358
1419
|
# If it's not yet enabled then: create extension ltree;
|
1359
1420
|
val %>
|
1360
|
-
<% when :binary
|
1421
|
+
<% when :binary %>
|
1422
|
+
<%= is_revert = false
|
1423
|
+
if val
|
1424
|
+
# %%% This same kind of geography check is done two other times above ... would be great to DRY it up.
|
1425
|
+
if val.length < 31 && (val.length - 6) % 8 == 0 && val[0..5].bytes == [230, 16, 0, 0, 1, 12]
|
1426
|
+
display_value('geography', val)
|
1427
|
+
else
|
1428
|
+
display_binary(val)
|
1429
|
+
end.html_safe
|
1430
|
+
end %>
|
1431
|
+
<% when :primary_key
|
1361
1432
|
is_revert = false %>
|
1362
1433
|
<% else %>
|
1363
1434
|
<%= is_revert = false
|
@@ -1381,8 +1452,8 @@ end
|
|
1381
1452
|
<% end %>
|
1382
1453
|
|
1383
1454
|
#{unless args.first == 'new'
|
1384
|
-
# Was: confirm_are_you_sure = ActionView.version < ::Gem::Version.new('7.0') ? "data: { confirm: 'Delete
|
1385
|
-
confirm_are_you_sure = "data: { confirm: 'Delete
|
1455
|
+
# 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?' } }"
|
1456
|
+
confirm_are_you_sure = "data: { confirm: 'Delete #\{model_name} -- Are you sure?' }"
|
1386
1457
|
hms_headers.each_with_object(+'') do |hm, s|
|
1387
1458
|
# %%% Would be able to remove this when multiple foreign keys to same destination becomes bulletproof
|
1388
1459
|
next if hm.first.options[:through] && !hm.first.through_reflection
|
@@ -1390,11 +1461,24 @@ end
|
|
1390
1461
|
if (pk = hm.first.klass.primary_key)
|
1391
1462
|
hm_singular_name = (hm_name = hm.first.name.to_s).singularize.underscore
|
1392
1463
|
obj_pk = (pk.is_a?(Array) ? pk : [pk]).each_with_object([]) { |pk_part, s| s << "#{hm_singular_name}.#{pk_part}" }.join(', ')
|
1464
|
+
poly_fix = if (poly_type = (hm.first.options[:as] && hm.first.type))
|
1465
|
+
"
|
1466
|
+
# Let's fix an unexpected \"feature\" of AR -- when going through a polymorphic has_many
|
1467
|
+
# association that points to an STI model then filtering for the __able_type column is done
|
1468
|
+
# with a .where(). And the polymorphic class name it points to is the base class name of
|
1469
|
+
# the STI model instead of its subclass.
|
1470
|
+
if (poly_type = #{poly_type.inspect}) &&
|
1471
|
+
@#{obj_name}.respond_to?(:#{@_brick_model.inheritance_column}) &&
|
1472
|
+
(base_type = collection.where_values_hash[poly_type])
|
1473
|
+
collection = collection.rewhere(poly_type => [base_type, @#{obj_name}.#{@_brick_model.inheritance_column}])
|
1474
|
+
end"
|
1475
|
+
end
|
1393
1476
|
s << "<table id=\"#{hm_name}\" class=\"shadow\">
|
1394
|
-
<tr><th>#{hm[3]}</th></tr>
|
1477
|
+
<tr><th>#{hm[1]}#{' poly' if hm[0].options[:as]} #{hm[3]}</th></tr>
|
1395
1478
|
<% collection = @#{obj_name}.#{hm_name}
|
1396
1479
|
collection = case collection
|
1397
|
-
when ActiveRecord::Associations::CollectionProxy
|
1480
|
+
when ActiveRecord::Associations::CollectionProxy#{
|
1481
|
+
poly_fix}
|
1398
1482
|
collection.order(#{pk.inspect})
|
1399
1483
|
when ActiveRecord::Base # Object from a has_one
|
1400
1484
|
[collection]
|
@@ -1576,11 +1660,10 @@ document.querySelectorAll(\"input, select\").forEach(function (inp) {
|
|
1576
1660
|
private
|
1577
1661
|
|
1578
1662
|
alias _brick_render_template render_template
|
1579
|
-
def render_template(view, template, *args)
|
1580
|
-
|
1581
|
-
|
1582
|
-
|
1583
|
-
end
|
1663
|
+
def render_template(view, template, layout_name, *args)
|
1664
|
+
layout_name = nil if (is_brick = template.instance_variable_get(:@is_brick)) && layout_name.is_a?(Proc)
|
1665
|
+
result = _brick_render_template(view, template, layout_name, *args)
|
1666
|
+
Apartment::Tenant.switch!(::Brick.apartment_default_tenant) if is_brick && ::Brick.apartment_multitenant
|
1584
1667
|
result
|
1585
1668
|
end
|
1586
1669
|
end # TemplateRenderer
|
@@ -3,7 +3,7 @@ module Brick::Rails::FormTags
|
|
3
3
|
def brick_grid(relation, bt_descrip, sequence = nil, inclusions, exclusions,
|
4
4
|
cols, poly_cols, bts, hms_keys, hms_cols)
|
5
5
|
out = "<table id=\"headerTop\"></table>
|
6
|
-
<table id=\"#{relation.table_name}\" class=\"shadow\">
|
6
|
+
<table id=\"#{relation.table_name.split('.').last}\" class=\"shadow\">
|
7
7
|
<thead><tr>"
|
8
8
|
pk = (klass = relation.klass).primary_key || []
|
9
9
|
pk = [pk] unless pk.is_a?(Array)
|
@@ -90,6 +90,7 @@ module Brick::Rails::FormTags
|
|
90
90
|
# 0..62 because Postgres column names are limited to 63 characters
|
91
91
|
obj, descrips[0..-2].map { |id| obj.send(id.last[0..62]) }, bt_id_col
|
92
92
|
)
|
93
|
+
bt_txt = display_binary(bt_txt).html_safe if bt_txt&.encoding&.name == 'ASCII-8BIT'
|
93
94
|
bt_txt ||= "<span class=\"orphan\"><< Orphaned ID: #{val} >></span>" if val
|
94
95
|
bt_id = bt_id_col&.map { |id_col| obj.respond_to?(id_sym = id_col.to_sym) ? obj.send(id_sym) : id_col }
|
95
96
|
out << (bt_id&.first ? link_to(bt_txt, send("#{bt_class.base_class._brick_index(:singular)}_path".to_sym, bt_id)) : bt_txt || '')
|
data/lib/brick/version_number.rb
CHANGED
data/lib/brick.rb
CHANGED
@@ -26,7 +26,7 @@ end
|
|
26
26
|
require 'brick/util'
|
27
27
|
|
28
28
|
# Allow ActiveRecord < 3.2 to work with Ruby 2.7 and later
|
29
|
-
if (ruby_version = ::Gem::Version.new(RUBY_VERSION)) >= ::Gem::Version.new('2.7')
|
29
|
+
if (is_ruby_2_7 = (ruby_version = ::Gem::Version.new(RUBY_VERSION)) >= ::Gem::Version.new('2.7'))
|
30
30
|
if ActiveRecord.version < ::Gem::Version.new('3.2')
|
31
31
|
# Remove circular reference for "now"
|
32
32
|
::Brick::Util._patch_require(
|
@@ -1043,6 +1043,18 @@ ActiveSupport.on_load(:active_record) do
|
|
1043
1043
|
end
|
1044
1044
|
# rubocop:enable Lint/ConstantDefinitionInBlock
|
1045
1045
|
|
1046
|
+
arsc = ::ActiveRecord::StatementCache
|
1047
|
+
if is_ruby_2_7 && (params = arsc.method(:create).parameters).length == 2 && params.last == [:opt, :block]
|
1048
|
+
arsc.class_exec do
|
1049
|
+
def self.create(connection, callable = nil, &block)
|
1050
|
+
relation = (callable || block).call ::ActiveRecord::StatementCache::Params.new
|
1051
|
+
bind_map = ::ActiveRecord::StatementCache::BindMap.new relation.bound_attributes
|
1052
|
+
query_builder = connection.cacheable_query(self, relation.arel)
|
1053
|
+
new query_builder, bind_map
|
1054
|
+
end
|
1055
|
+
end
|
1056
|
+
end
|
1057
|
+
|
1046
1058
|
# Rails < 4.2 is not innately compatible with Ruby 2.4 and later, and comes up with:
|
1047
1059
|
# "TypeError: Cannot visit Integer" unless we patch like this:
|
1048
1060
|
if ruby_version >= ::Gem::Version.new('2.4') &&
|
@@ -1081,11 +1093,54 @@ ActiveSupport.on_load(:active_record) do
|
|
1081
1093
|
end
|
1082
1094
|
end
|
1083
1095
|
|
1096
|
+
if Psych.respond_to?(:unsafe_load) && ActiveRecord.version < ::Gem::Version.new('6.1')
|
1097
|
+
Psych.class_exec do
|
1098
|
+
class << self
|
1099
|
+
alias _original_load load
|
1100
|
+
def load(yaml, *args, **kwargs)
|
1101
|
+
if caller.first.end_with?("`database_configuration'") && kwargs[:aliases].nil?
|
1102
|
+
kwargs[:aliases] = true
|
1103
|
+
end
|
1104
|
+
_original_load(yaml, *args, **kwargs)
|
1105
|
+
end
|
1106
|
+
end
|
1107
|
+
end
|
1108
|
+
end
|
1109
|
+
|
1110
|
+
# def aliased_table_for(arel_table, table_name = nil)
|
1111
|
+
# table_name ||= arel_table.name
|
1112
|
+
|
1113
|
+
# if aliases[table_name] == 0
|
1114
|
+
# # If it's zero, we can have our table_name
|
1115
|
+
# aliases[table_name] = 1
|
1116
|
+
# arel_table = arel_table.alias(table_name) if arel_table.name != table_name
|
1117
|
+
# else
|
1118
|
+
# # Otherwise, we need to use an alias
|
1119
|
+
# aliased_name = @connection.table_alias_for(yield)
|
1120
|
+
|
1121
|
+
# # Update the count
|
1122
|
+
# count = aliases[aliased_name] += 1
|
1123
|
+
|
1124
|
+
# aliased_name = "#{truncate(aliased_name)}_#{count}" if count > 1
|
1125
|
+
|
1126
|
+
# arel_table = arel_table.alias(aliased_name)
|
1127
|
+
# end
|
1128
|
+
|
1129
|
+
# arel_table
|
1130
|
+
# end
|
1131
|
+
# def aliased_table_for(table_name, aliased_name, type_caster)
|
1132
|
+
|
1084
1133
|
class ActiveRecord::Associations::JoinDependency
|
1085
|
-
if JoinBase.instance_method(:initialize).arity == 2 # Older ActiveRecord
|
1086
|
-
def initialize(base, associations, joins)
|
1087
|
-
|
1088
|
-
|
1134
|
+
if JoinBase.instance_method(:initialize).arity == 2 # Older ActiveRecord <= 5.1?
|
1135
|
+
def initialize(base, associations, joins, eager_loading: true)
|
1136
|
+
araat = ::ActiveRecord::Associations::AliasTracker
|
1137
|
+
if araat.respond_to?(:create_with_joins) # Rails 5.0 and 5.1
|
1138
|
+
@alias_tracker = araat.create_with_joins(base.connection, base.table_name, joins)
|
1139
|
+
@eager_loading = eager_loading # (Unused in Rails 5.0)
|
1140
|
+
else # Rails 4.2
|
1141
|
+
@alias_tracker = araat.create(base.connection, joins)
|
1142
|
+
@alias_tracker.aliased_table_for(base, base.table_name) # Updates the count for base.table_name to 1
|
1143
|
+
end
|
1089
1144
|
tree = self.class.make_tree associations
|
1090
1145
|
|
1091
1146
|
# Provide a way to find the original relation that this tree is being used for
|
@@ -1098,7 +1153,7 @@ ActiveSupport.on_load(:active_record) do
|
|
1098
1153
|
@join_root.children.each { |child| construct_tables! @join_root, child }
|
1099
1154
|
end
|
1100
1155
|
|
1101
|
-
else # For ActiveRecord 5.
|
1156
|
+
else # For ActiveRecord 5.2 - 7.1
|
1102
1157
|
|
1103
1158
|
def initialize(base, table, associations, join_type = nil)
|
1104
1159
|
tree = self.class.make_tree associations
|
@@ -1245,13 +1300,13 @@ module ActiveRecord
|
|
1245
1300
|
|
1246
1301
|
if private_instance_methods.include?(:build_join_query)
|
1247
1302
|
alias _brick_build_join_query build_join_query
|
1248
|
-
def build_join_query(manager, buckets, *args)
|
1303
|
+
def build_join_query(manager, buckets, *args) # , **kwargs)
|
1249
1304
|
# %%% Better way to bring relation into the mix
|
1250
1305
|
if (aj = buckets.fetch(:association_join, nil))
|
1251
1306
|
aj.instance_variable_set(:@relation, self)
|
1252
1307
|
end
|
1253
1308
|
|
1254
|
-
_brick_build_join_query(manager, buckets, *args)
|
1309
|
+
_brick_build_join_query(manager, buckets, *args) # , **kwargs)
|
1255
1310
|
end
|
1256
1311
|
|
1257
1312
|
else
|
@@ -1433,4 +1488,85 @@ if Gem::Specification.all_names.any? { |g| g.start_with?('ransack-') }
|
|
1433
1488
|
end
|
1434
1489
|
end
|
1435
1490
|
|
1491
|
+
# Keyword arguments updates for Rails <= 5.2.x and Ruby >= 3.0
|
1492
|
+
if ActiveRecord.version < ::Gem::Version.new('6.0') && ruby_version >= ::Gem::Version.new('3.0')
|
1493
|
+
admsm = ActionDispatch::MiddlewareStack::Middleware
|
1494
|
+
admsm.class_exec do
|
1495
|
+
# redefine #build
|
1496
|
+
def build(app, **kwargs)
|
1497
|
+
# puts klass.name
|
1498
|
+
if args.length > 1 && args.last.is_a?(Hash)
|
1499
|
+
kwargs.merge!(args.pop)
|
1500
|
+
end
|
1501
|
+
# binding.pry if klass == ActionDispatch::Static # ActionDispatch::Reloader
|
1502
|
+
klass.new(app, *args, **kwargs, &block)
|
1503
|
+
end
|
1504
|
+
end
|
1505
|
+
|
1506
|
+
require 'active_model'
|
1507
|
+
require 'active_model/type'
|
1508
|
+
require 'active_model/type/value'
|
1509
|
+
class ActiveModel::Type::Value
|
1510
|
+
def initialize(*args, precision: nil, limit: nil, scale: nil)
|
1511
|
+
@precision = precision
|
1512
|
+
@scale = scale
|
1513
|
+
@limit = limit
|
1514
|
+
end
|
1515
|
+
end
|
1516
|
+
|
1517
|
+
if Object.const_defined?('I18n')
|
1518
|
+
module I18n::Base
|
1519
|
+
alias _brick_translate translate
|
1520
|
+
def translate(key = nil, *args, throw: false, raise: false, locale: nil, **options)
|
1521
|
+
options.merge!(args.pop) if args.length > 0 && args.last.is_a?(Hash)
|
1522
|
+
_brick_translate(key = nil, throw: false, raise: false, locale: nil, **options)
|
1523
|
+
end
|
1524
|
+
end
|
1525
|
+
end
|
1526
|
+
|
1527
|
+
module ActionController::RequestForgeryProtection
|
1528
|
+
private
|
1529
|
+
|
1530
|
+
# Creates the authenticity token for the current request.
|
1531
|
+
def form_authenticity_token(*args, form_options: {}) # :doc:
|
1532
|
+
form_options.merge!(args.pop) if args.length > 0 && args.last.is_a?(Hash)
|
1533
|
+
masked_authenticity_token(session, form_options: form_options)
|
1534
|
+
end
|
1535
|
+
end
|
1536
|
+
|
1537
|
+
module ActiveSupport
|
1538
|
+
class MessageEncryptor
|
1539
|
+
def encrypt_and_sign(value, *args, expires_at: nil, expires_in: nil, purpose: nil)
|
1540
|
+
encrypted = if method(:_encrypt).arity == 1
|
1541
|
+
_encrypt(value) # Rails <= 5.1
|
1542
|
+
else
|
1543
|
+
if args.length > 0 && args.last.is_a?(Hash)
|
1544
|
+
expires_at ||= args.last[:expires_at]
|
1545
|
+
expires_in ||= args.last[:expires_in]
|
1546
|
+
purpose ||= args.last[:purpose]
|
1547
|
+
end
|
1548
|
+
_encrypt(value, expires_at: expires_at, expires_in: expires_in, purpose: purpose)
|
1549
|
+
end
|
1550
|
+
verifier.generate(encrypted)
|
1551
|
+
end
|
1552
|
+
end
|
1553
|
+
if const_defined?('Messages')
|
1554
|
+
class Messages::Metadata
|
1555
|
+
def self.wrap(message, *args, expires_at: nil, expires_in: nil, purpose: nil)
|
1556
|
+
if args.length > 0 && args.last.is_a?(Hash)
|
1557
|
+
expires_at ||= args.last[:expires_at]
|
1558
|
+
expires_in ||= args.last[:expires_in]
|
1559
|
+
purpose ||= args.last[:purpose]
|
1560
|
+
end
|
1561
|
+
if expires_at || expires_in || purpose
|
1562
|
+
JSON.encode new(encode(message), pick_expiry(expires_at, expires_in), purpose)
|
1563
|
+
else
|
1564
|
+
message
|
1565
|
+
end
|
1566
|
+
end
|
1567
|
+
end
|
1568
|
+
end
|
1569
|
+
end
|
1570
|
+
end
|
1571
|
+
|
1436
1572
|
require 'brick/extensions'
|
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.103
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lorin Thwaits
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-01-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -164,6 +164,20 @@ 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'
|
167
181
|
- !ruby/object:Gem::Dependency
|
168
182
|
name: pg
|
169
183
|
requirement: !ruby/object:Gem::Requirement
|