brick 1.0.125 → 1.0.127
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/brick/compatibility.rb +9 -11
- data/lib/brick/extensions.rb +41 -11
- data/lib/brick/frameworks/rails/engine.rb +107 -266
- data/lib/brick/frameworks/rails/form_builder.rb +187 -0
- data/lib/brick/frameworks/rails/form_tags.rb +1 -1
- data/lib/brick/version_number.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7a424ad95046c33fae8463661b1fb53d770e44e37b503cb68b30fce5725c5ebd
|
4
|
+
data.tar.gz: 2fc4b004e49497b1b15c864a646717c162e7d7d55edf6913e916fab86ebbcbb7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5ebf6939ba66e746baf8c84b347630ec4e68951b23dc1efcd72bff47b3b6550c3c8d3444194489aa227a3be153b387552951fdd0fec03dc66a73306df6d6f0d4
|
7
|
+
data.tar.gz: e3a90e24d98d3bcb47d09e628df9958b101f8dfb9998c97307b791664e8a8b429d12febe73a1e3e322ef3aab054a9e0a103614f2053f58f1b0d2d3e580c9c083
|
data/lib/brick/compatibility.rb
CHANGED
@@ -19,19 +19,17 @@ unless ActiveSupport.respond_to?(:version)
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
end
|
22
|
-
if Object.const_defined?('ActionPack')
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
::Gem::Version.new(ActionPack::VERSION::STRING)
|
27
|
-
end
|
22
|
+
if Object.const_defined?('ActionPack') && !ActionPack.respond_to?(:version)
|
23
|
+
module ActionPack
|
24
|
+
def self.version
|
25
|
+
::Gem::Version.new(ActionPack::VERSION::STRING)
|
28
26
|
end
|
29
27
|
end
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
28
|
+
end
|
29
|
+
if Object.const_defined?('ActionView') && !ActionView.respond_to?(:version)
|
30
|
+
module ActionView
|
31
|
+
def self.version
|
32
|
+
ActionPack.version
|
35
33
|
end
|
36
34
|
end
|
37
35
|
end
|
data/lib/brick/extensions.rb
CHANGED
@@ -231,6 +231,9 @@ module ActiveRecord
|
|
231
231
|
if this_obj.is_a?(ActiveRecord::Base) && (obj_descrip = this_obj.class.brick_descrip(this_obj))
|
232
232
|
this_obj = obj_descrip
|
233
233
|
end
|
234
|
+
if this_obj.is_a?(ActiveStorage::Filename) && this_obj.instance_variable_get(:@filename).nil?
|
235
|
+
this_obj.instance_variable_set(:@filename, '')
|
236
|
+
end
|
234
237
|
this_obj&.to_s || ''
|
235
238
|
end
|
236
239
|
is_brackets_have_content = true unless datum.blank?
|
@@ -914,8 +917,23 @@ end
|
|
914
917
|
|
915
918
|
if Object.const_defined?('ActionView')
|
916
919
|
require 'brick/frameworks/rails/form_tags'
|
917
|
-
|
918
|
-
|
920
|
+
require 'brick/frameworks/rails/form_builder'
|
921
|
+
module ActionView::Helpers
|
922
|
+
module FormTagHelper
|
923
|
+
include ::Brick::Rails::FormTags
|
924
|
+
end
|
925
|
+
FormBuilder.class_exec do
|
926
|
+
include ::Brick::Rails::FormBuilder
|
927
|
+
end
|
928
|
+
end
|
929
|
+
|
930
|
+
# FormBuilder#field_id isn't available in Rails < 7.0. This is a rudimentary version with no `index`.
|
931
|
+
unless ActionView::Helpers::FormBuilder.methods.include?(:field_id)
|
932
|
+
ActionView::Helpers::FormBuilder.class_exec do
|
933
|
+
def field_id(method)
|
934
|
+
[object_name, method.to_s].join('_')
|
935
|
+
end
|
936
|
+
end
|
919
937
|
end
|
920
938
|
end
|
921
939
|
|
@@ -1817,7 +1835,13 @@ class Object
|
|
1817
1835
|
code << " end\n"
|
1818
1836
|
self.define_method :new do
|
1819
1837
|
_schema, @_is_show_schema_list = ::Brick.set_db_schema(params)
|
1820
|
-
|
1838
|
+
if (new_obj = model.new).respond_to?(:serializable_hash)
|
1839
|
+
# Convert any Filename objects with nil into an empty string so that #encode can be called on them
|
1840
|
+
new_obj.serializable_hash.each do |k, v|
|
1841
|
+
new_obj.send("#{k}=", ActiveStorage::Filename.new('')) if v.is_a?(ActiveStorage::Filename) && !v.instance_variable_get(:@filename)
|
1842
|
+
end
|
1843
|
+
end
|
1844
|
+
instance_variable_set("@#{singular_table_name}".to_sym, new_obj)
|
1821
1845
|
end
|
1822
1846
|
|
1823
1847
|
params_name_sym = (params_name = "#{singular_table_name}_params").to_sym
|
@@ -2113,7 +2137,6 @@ end.class_exec do
|
|
2113
2137
|
load apartment_initializer
|
2114
2138
|
@_apartment_loaded = true
|
2115
2139
|
end
|
2116
|
-
apartment_excluded = Apartment.excluded_models
|
2117
2140
|
end
|
2118
2141
|
# Only for Postgres (Doesn't work in sqlite3 or MySQL)
|
2119
2142
|
# puts ActiveRecord::Base.execute_sql("SELECT current_setting('SEARCH_PATH')").to_a.inspect
|
@@ -2203,7 +2226,7 @@ end.class_exec do
|
|
2203
2226
|
# If Apartment gem lists the table as being associated with a non-tenanted model then use whatever it thinks
|
2204
2227
|
# is the default schema, usually 'public'.
|
2205
2228
|
schema_name = if ::Brick.config.schema_behavior[:multitenant]
|
2206
|
-
::Brick.apartment_default_tenant if
|
2229
|
+
::Brick.apartment_default_tenant if ::Brick.is_apartment_excluded_table(r['relation_name'])
|
2207
2230
|
elsif ![schema, 'public'].include?(r['schema'])
|
2208
2231
|
r['schema']
|
2209
2232
|
end
|
@@ -2353,7 +2376,7 @@ ORDER BY 1, 2, c.internal_column_id, acc.position"
|
|
2353
2376
|
fk_references&.each do |fk|
|
2354
2377
|
fk = fk.values unless fk.is_a?(Array)
|
2355
2378
|
# Multitenancy makes things a little more general overall, except for non-tenanted tables
|
2356
|
-
if
|
2379
|
+
if ::Brick.is_apartment_excluded_table(::Brick.namify(fk[1]))
|
2357
2380
|
fk[0] = ::Brick.apartment_default_tenant
|
2358
2381
|
elsif (is_postgres && (fk[0] == 'public' || (multitenancy && fk[0] == schema))) ||
|
2359
2382
|
(::Brick.is_oracle && fk[0] == schema) ||
|
@@ -2361,7 +2384,7 @@ ORDER BY 1, 2, c.internal_column_id, acc.position"
|
|
2361
2384
|
(!is_postgres && !::Brick.is_oracle && !is_mssql && ['mysql', 'performance_schema', 'sys'].exclude?(fk[0]))
|
2362
2385
|
fk[0] = nil
|
2363
2386
|
end
|
2364
|
-
if
|
2387
|
+
if ::Brick.is_apartment_excluded_table(fk[4])
|
2365
2388
|
fk[3] = ::Brick.apartment_default_tenant
|
2366
2389
|
elsif (is_postgres && (fk[3] == 'public' || (multitenancy && fk[3] == schema))) ||
|
2367
2390
|
(::Brick.is_oracle && fk[3] == schema) ||
|
@@ -2537,8 +2560,7 @@ module Brick
|
|
2537
2560
|
# %%% Temporary schema patch
|
2538
2561
|
for_tbl = fk[1]
|
2539
2562
|
fk_namified = ::Brick.namify(fk[1])
|
2540
|
-
|
2541
|
-
fk[0] = ::Brick.apartment_default_tenant if apartment && apartment.excluded_models.include?(fk_namified.singularize.camelize)
|
2563
|
+
fk[0] = ::Brick.apartment_default_tenant if ::Brick.is_apartment_excluded_table(fk_namified)
|
2542
2564
|
fk[1] = "#{fk[0]}.#{fk[1]}" if fk[0] # && fk[0] != ::Brick.default_schema
|
2543
2565
|
bts = (relation = relations.fetch(fk[1], nil))&.fetch(:fks) { relation[:fks] = {} }
|
2544
2566
|
|
@@ -2553,7 +2575,7 @@ module Brick
|
|
2553
2575
|
is_schema = if ::Brick.config.schema_behavior[:multitenant]
|
2554
2576
|
# If Apartment gem lists the primary table as being associated with a non-tenanted model
|
2555
2577
|
# then use 'public' schema for the primary table
|
2556
|
-
if
|
2578
|
+
if ::Brick.is_apartment_excluded_table(fk[4])
|
2557
2579
|
fk[3] = ::Brick.apartment_default_tenant
|
2558
2580
|
true
|
2559
2581
|
end
|
@@ -2630,7 +2652,7 @@ module Brick
|
|
2630
2652
|
end
|
2631
2653
|
assoc_hm[:alternate_name] = "#{assoc_hm[:alternate_name]}_#{bt_assoc_name}" unless assoc_hm[:alternate_name] == bt_assoc_name
|
2632
2654
|
else
|
2633
|
-
inv_tbl = if ::Brick.config.schema_behavior[:multitenant] &&
|
2655
|
+
inv_tbl = if ::Brick.config.schema_behavior[:multitenant] && Object.const_defined?('Apartment') && fk[0] == ::Brick.apartment_default_tenant
|
2634
2656
|
for_tbl
|
2635
2657
|
else
|
2636
2658
|
fk[1]
|
@@ -2800,5 +2822,13 @@ module Brick
|
|
2800
2822
|
def _class_pk(dotted_name, multitenant)
|
2801
2823
|
Object.const_get((multitenant ? [dotted_name.split('.').last] : dotted_name.split('.')).map { |nm| "::#{nm.singularize.camelize}" }.join).primary_key
|
2802
2824
|
end
|
2825
|
+
|
2826
|
+
def is_apartment_excluded_table(tbl)
|
2827
|
+
if Object.const_defined?('Apartment')
|
2828
|
+
tbl_klass = (tnp = ::Brick.config.table_name_prefixes&.find { |k, _v| tbl.start_with?(k) }) ? +"#{tnp.last}::" : +''
|
2829
|
+
tbl_klass << tbl[tnp&.first&.length || 0..-1].singularize.camelize
|
2830
|
+
Apartment.excluded_models&.include?(tbl_klass)
|
2831
|
+
end
|
2832
|
+
end
|
2803
2833
|
end
|
2804
2834
|
end
|
@@ -2,36 +2,103 @@
|
|
2
2
|
|
3
3
|
module Brick
|
4
4
|
module Rails
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
5
|
+
class << self
|
6
|
+
def display_value(col_type, val)
|
7
|
+
is_mssql_geography = nil
|
8
|
+
# 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)
|
9
|
+
if col_type == :binary && val && val.length < 31 && (val.length - 6) % 8 == 0 && val[0..5].bytes == [230, 16, 0, 0, 1, 12]
|
10
|
+
col_type = 'geography'
|
11
|
+
is_mssql_geography = true
|
12
|
+
end
|
13
|
+
case col_type
|
14
|
+
when 'geometry', 'geography'
|
15
|
+
if Object.const_defined?('RGeo')
|
16
|
+
@is_mysql = ['Mysql2', 'Trilogy'].include?(ActiveRecord::Base.connection.adapter_name) if @is_mysql.nil?
|
17
|
+
@is_mssql = ActiveRecord::Base.connection.adapter_name == 'SQLServer' if @is_mssql.nil?
|
18
|
+
val_err = nil
|
19
|
+
|
20
|
+
if @is_mysql || (is_mssql_geography ||=
|
21
|
+
(@is_mssql ||
|
22
|
+
(val && val.length < 31 && (val.length - 6) % 8 == 0 && val[0..5].bytes == [230, 16, 0, 0, 1, 12])
|
23
|
+
)
|
24
|
+
)
|
25
|
+
# MySQL's \"Internal Geometry Format\" and MSSQL's Geography are like WKB, but with an initial 4 bytes that indicates the SRID.
|
26
|
+
if (srid = val&.[](0..3)&.unpack('I'))
|
27
|
+
val = val.dup.force_encoding('BINARY')[4..-1].bytes
|
28
|
+
|
29
|
+
# MSSQL spatial bitwise flags, often 0C for a point:
|
30
|
+
# xxxx xxx1 = HasZValues
|
31
|
+
# xxxx xx1x = HasMValues
|
32
|
+
# xxxx x1xx = IsValid
|
33
|
+
# xxxx 1xxx = IsSinglePoint
|
34
|
+
# xxx1 xxxx = IsSingleLineSegment
|
35
|
+
# xx1x xxxx = IsWholeGlobe
|
36
|
+
# Convert Microsoft's unique geography binary to standard WKB
|
37
|
+
# (MSSQL point usually has two doubles, lng / lat, and can also have Z)
|
38
|
+
if is_mssql_geography
|
39
|
+
if val[0] == 1 && (val[1] & 8 > 0) && # Single point?
|
40
|
+
(val.length - 2) % 8 == 0 && val.length < 27 # And containing up to three 8-byte values?
|
41
|
+
val = [0, 0, 0, 0, 1] + val[2..-1].reverse
|
42
|
+
else
|
43
|
+
val_err = '(Microsoft internal SQL geography type)'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
unless val_err || val.nil?
|
49
|
+
if (geometry = RGeo::WKRep::WKBParser.new.parse(val.pack('c*'))).is_a?(RGeo::Cartesian::PointImpl) &&
|
50
|
+
!(geometry.y == 0.0 && geometry.x == 0.0)
|
51
|
+
# 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
|
52
|
+
geometry = "<a href=\"https://www.google.com/maps/place/#{geometry.y}+#{geometry.x}/@#{geometry.y},#{geometry.x},12z\" target=\"blank\">#{geometry.to_s}</a>"
|
53
|
+
end
|
54
|
+
val = geometry
|
55
|
+
end
|
56
|
+
val_err || val
|
57
|
+
else
|
58
|
+
'(Add RGeo gem to parse geometry detail)'
|
59
|
+
end
|
60
|
+
when :binary
|
61
|
+
::Brick::Rails.display_binary(val) if val
|
62
|
+
else
|
63
|
+
if col_type
|
64
|
+
::Brick::Rails::FormBuilder.hide_bcrypt(val, col_type == :xml)
|
65
|
+
else
|
66
|
+
'?'
|
67
|
+
end
|
68
|
+
end
|
25
69
|
end
|
26
70
|
|
27
|
-
|
28
|
-
|
29
|
-
|
71
|
+
def display_binary(val)
|
72
|
+
@image_signatures ||= { (+"\xFF\xD8\xFF\xEE").force_encoding('ASCII-8BIT') => 'jpeg',
|
73
|
+
(+"\xFF\xD8\xFF\xE0\x00\x10\x4A\x46\x49\x46\x00\x01").force_encoding('ASCII-8BIT') => 'jpeg',
|
74
|
+
(+"\x89PNG\r\n\x1A\n").force_encoding('ASCII-8BIT') => 'png',
|
75
|
+
'<svg' => 'svg+xml', # %%% Not yet very good detection for SVG
|
76
|
+
(+'BM').force_encoding('ASCII-8BIT') => 'bmp',
|
77
|
+
(+'GIF87a').force_encoding('ASCII-8BIT') => 'gif',
|
78
|
+
(+'GIF89a').force_encoding('ASCII-8BIT') => 'gif' }
|
79
|
+
|
80
|
+
if val[0..1] == "\x15\x1C" # One of those goofy Microsoft OLE containers?
|
81
|
+
package_header_length = val[2..3].bytes.reverse.inject(0) {|m, b| (m << 8) + b }
|
82
|
+
# This will often be just FF FF FF FF
|
83
|
+
# object_size = val[16..19].bytes.reverse.inject(0) {|m, b| (m << 8) + b }
|
84
|
+
friendly_and_class_names = val[20...package_header_length].split("\0")
|
85
|
+
object_type_name_length = val[package_header_length + 8..package_header_length+11].bytes.reverse.inject(0) {|m, b| (m << 8) + b }
|
86
|
+
friendly_and_class_names << val[package_header_length + 12...package_header_length + 12 + object_type_name_length].strip
|
87
|
+
# friendly_and_class_names will now be something like: ['Bitmap Image', 'Paint.Picture', 'PBrush']
|
88
|
+
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 }
|
89
|
+
object_start = package_header_length + 24 + object_type_name_length
|
90
|
+
val = val[object_start...object_start + real_object_size]
|
91
|
+
end
|
92
|
+
|
93
|
+
if (signature = @image_signatures.find { |k, _v| val[0...k.length] == k })
|
94
|
+
if val.length < 500_000
|
95
|
+
"<img src=\"data:image/#{signature.last};base64,#{Base64.encode64(val)}\">"
|
96
|
+
else
|
97
|
+
"< #{signature.last} image, #{val.length} bytes >"
|
98
|
+
end
|
30
99
|
else
|
31
|
-
"< 
|
100
|
+
"< Binary, #{val.length} bytes >"
|
32
101
|
end
|
33
|
-
else
|
34
|
-
"< Binary, #{val.length} bytes >"
|
35
102
|
end
|
36
103
|
end
|
37
104
|
|
@@ -878,138 +945,7 @@ input+svg.revert {
|
|
878
945
|
window.addEventListener(\"popstate\", function () { location.reload(true); });
|
879
946
|
</script>
|
880
947
|
|
881
|
-
<%
|
882
|
-
is_includes_json = nil
|
883
|
-
is_includes_text = nil
|
884
|
-
def is_bcrypt?(val)
|
885
|
-
val.is_a?(String) && val.length == 60 && val.start_with?('$2a$')
|
886
|
-
end
|
887
|
-
def hide_bcrypt(val, is_xml = nil, max_len = 200)
|
888
|
-
if is_bcrypt?(val)
|
889
|
-
'(hidden)'
|
890
|
-
else
|
891
|
-
if val.is_a?(String)
|
892
|
-
val = val.dup.force_encoding('UTF-8').strip
|
893
|
-
return CGI.escapeHTML(val) if is_xml
|
894
|
-
|
895
|
-
if val.length > max_len
|
896
|
-
if val[0] == '<' # Seems to be HTML?
|
897
|
-
cur_len = 0
|
898
|
-
cur_idx = 0
|
899
|
-
# Find which HTML tags we might be inside so we can apply ending tags to balance
|
900
|
-
element_name = nil
|
901
|
-
in_closing = nil
|
902
|
-
elements = []
|
903
|
-
val.each_char do |ch|
|
904
|
-
case ch
|
905
|
-
when '<'
|
906
|
-
element_name = +''
|
907
|
-
when '/' # First character of tag is '/'?
|
908
|
-
in_closing = true if element_name == ''
|
909
|
-
when '>'
|
910
|
-
if element_name
|
911
|
-
if in_closing
|
912
|
-
if (idx = elements.index { |tag| tag.downcase == element_name.downcase })
|
913
|
-
elements.delete_at(idx)
|
914
|
-
end
|
915
|
-
elsif (tag_name = element_name.split.first).present?
|
916
|
-
elements.unshift(tag_name)
|
917
|
-
end
|
918
|
-
element_name = nil
|
919
|
-
in_closing = nil
|
920
|
-
end
|
921
|
-
else
|
922
|
-
element_name << ch if element_name
|
923
|
-
end
|
924
|
-
cur_idx += 1
|
925
|
-
# Unless it's inside wickets then this is real text content, and see if we're at the limit
|
926
|
-
break if element_name.nil? && ((cur_len += 1) > max_len)
|
927
|
-
end
|
928
|
-
val = val[0..cur_idx]
|
929
|
-
# Somehow still in the middle of an opening tag right at the end? (Should never happen)
|
930
|
-
if !in_closing && (tag_name = element_name&.split&.first)&.present?
|
931
|
-
elements.unshift(tag_name)
|
932
|
-
val << '>'
|
933
|
-
end
|
934
|
-
elements.each do |closing_tag|
|
935
|
-
val << \"</#\{closing_tag}>\"
|
936
|
-
end
|
937
|
-
else # Not HTML, just cut it at the length
|
938
|
-
val = val[0...max_len]
|
939
|
-
end
|
940
|
-
val = \"#\{val}...\"
|
941
|
-
end
|
942
|
-
val
|
943
|
-
else
|
944
|
-
val.to_s
|
945
|
-
end
|
946
|
-
end
|
947
|
-
end
|
948
|
-
def display_value(col_type, val)
|
949
|
-
is_mssql_geography = nil
|
950
|
-
# 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)
|
951
|
-
if col_type == :binary && val && val.length < 31 && (val.length - 6) % 8 == 0 && val[0..5].bytes == [230, 16, 0, 0, 1, 12]
|
952
|
-
col_type = 'geography'
|
953
|
-
is_mssql_geography = true
|
954
|
-
end
|
955
|
-
case col_type
|
956
|
-
when 'geometry', 'geography'
|
957
|
-
if Object.const_defined?('RGeo')
|
958
|
-
@is_mysql = ['Mysql2', 'Trilogy'].include?(ActiveRecord::Base.connection.adapter_name) if @is_mysql.nil?
|
959
|
-
@is_mssql = ActiveRecord::Base.connection.adapter_name == 'SQLServer' if @is_mssql.nil?
|
960
|
-
val_err = nil
|
961
|
-
|
962
|
-
if @is_mysql || (is_mssql_geography ||=
|
963
|
-
(@is_mssql ||
|
964
|
-
(val && val.length < 31 && (val.length - 6) % 8 == 0 && val[0..5].bytes == [230, 16, 0, 0, 1, 12])
|
965
|
-
)
|
966
|
-
)
|
967
|
-
# MySQL's \"Internal Geometry Format\" and MSSQL's Geography are like WKB, but with an initial 4 bytes that indicates the SRID.
|
968
|
-
if (srid = val&.[](0..3)&.unpack('I'))
|
969
|
-
val = val.dup.force_encoding('BINARY')[4..-1].bytes
|
970
|
-
|
971
|
-
# MSSQL spatial bitwise flags, often 0C for a point:
|
972
|
-
# xxxx xxx1 = HasZValues
|
973
|
-
# xxxx xx1x = HasMValues
|
974
|
-
# xxxx x1xx = IsValid
|
975
|
-
# xxxx 1xxx = IsSinglePoint
|
976
|
-
# xxx1 xxxx = IsSingleLineSegment
|
977
|
-
# xx1x xxxx = IsWholeGlobe
|
978
|
-
# Convert Microsoft's unique geography binary to standard WKB
|
979
|
-
# (MSSQL point usually has two doubles, lng / lat, and can also have Z)
|
980
|
-
if is_mssql_geography
|
981
|
-
if val[0] == 1 && (val[1] & 8 > 0) && # Single point?
|
982
|
-
(val.length - 2) % 8 == 0 && val.length < 27 # And containing up to three 8-byte values?
|
983
|
-
val = [0, 0, 0, 0, 1] + val[2..-1].reverse
|
984
|
-
else
|
985
|
-
val_err = '(Microsoft internal SQL geography type)'
|
986
|
-
end
|
987
|
-
end
|
988
|
-
end
|
989
|
-
end
|
990
|
-
unless val_err || val.nil?
|
991
|
-
if (geometry = RGeo::WKRep::WKBParser.new.parse(val.pack('c*'))).is_a?(RGeo::Cartesian::PointImpl) &&
|
992
|
-
!(geometry.y == 0.0 && geometry.x == 0.0)
|
993
|
-
# 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
|
994
|
-
geometry = \"<a href=\\\"https://www.google.com/maps/place/#\{geometry.y}+#\{geometry.x}/@#\{geometry.y},#\{geometry.x},12z\\\" target=\\\"blank\\\">#\{geometry.to_s}</a>\"
|
995
|
-
end
|
996
|
-
val = geometry
|
997
|
-
end
|
998
|
-
val_err || val
|
999
|
-
else
|
1000
|
-
'(Add RGeo gem to parse geometry detail)'
|
1001
|
-
end
|
1002
|
-
when :binary
|
1003
|
-
::Brick::Rails.display_binary(val) if val
|
1004
|
-
else
|
1005
|
-
if col_type
|
1006
|
-
hide_bcrypt(val, col_type == :xml)
|
1007
|
-
else
|
1008
|
-
'?'
|
1009
|
-
end
|
1010
|
-
end
|
1011
|
-
end
|
1012
|
-
|
948
|
+
<%
|
1013
949
|
# Accommodate composite primary keys that include strings with forward-slash characters
|
1014
950
|
def slashify(*vals)
|
1015
951
|
vals.map { |val_part| val_part.is_a?(String) ? val_part.gsub('/', '^^sl^^') : val_part }
|
@@ -1569,10 +1505,10 @@ end
|
|
1569
1505
|
<title><%=
|
1570
1506
|
base_model = (model = (obj = @#{obj_name})&.class).base_class
|
1571
1507
|
see_all_path = send(\"#\{base_model._brick_index}_path\")
|
1572
|
-
|
1573
|
-
|
1508
|
+
#{(inh_col = @_brick_model.inheritance_column).present? &&
|
1509
|
+
" if obj.respond_to?(:#{inh_col}) && (model_name = @#{obj_name}.#{inh_col}) != base_model.name
|
1574
1510
|
see_all_path << \"?#{inh_col}=#\{model_name}\"
|
1575
|
-
end
|
1511
|
+
end"}
|
1576
1512
|
page_title = (\"#\{model_name ||= model.name}: #\{obj&.brick_descrip || controller_name}\")
|
1577
1513
|
%></title>
|
1578
1514
|
</head>
|
@@ -1674,103 +1610,7 @@ end
|
|
1674
1610
|
<% end %>
|
1675
1611
|
</th>
|
1676
1612
|
<td>
|
1677
|
-
|
1678
|
-
<% dt_pickers = { datetime: 'datetimepicker', timestamp: 'datetimepicker', time: 'timepicker', date: 'datepicker' }
|
1679
|
-
html_options = {}
|
1680
|
-
html_options[:class] = 'dimmed' unless val
|
1681
|
-
is_revert = true
|
1682
|
-
if bt
|
1683
|
-
html_options[:prompt] = \"Select #\{bt_name\}\" %>
|
1684
|
-
<%= f.select k.to_sym, bt[3], { value: val || '^^^brick_NULL^^^' }, html_options %>
|
1685
|
-
<%= if (bt_obj = bt_class&.find_by(bt_pair[1] => val))
|
1686
|
-
link_to('⇛', send(\"#\{bt_class.base_class._brick_index(:singular)\}_path\".to_sym, bt_obj.send(bt_class.primary_key.to_sym)), { class: 'show-arrow' })
|
1687
|
-
elsif val
|
1688
|
-
\"<span class=\\\"orphan\\\">Orphaned ID: #\{val}</span>\".html_safe
|
1689
|
-
end %>
|
1690
|
-
<% elsif @_brick_monetized_attributes&.include?(k)
|
1691
|
-
%><%= f.text_field(k.to_sym, html_options.merge({ value: Money.new(val.to_i).format })) %><%
|
1692
|
-
else
|
1693
|
-
col_type = if model.json_column?(col)
|
1694
|
-
:json
|
1695
|
-
elsif col&.sql_type == 'geography'
|
1696
|
-
col.sql_type
|
1697
|
-
else
|
1698
|
-
col&.type
|
1699
|
-
end
|
1700
|
-
case (col_type ||= col&.sql_type)
|
1701
|
-
when :string, :text
|
1702
|
-
if is_bcrypt?(val) # || .readonly?
|
1703
|
-
is_revert = false %>
|
1704
|
-
<%= hide_bcrypt(val, nil, 1000) %>
|
1705
|
-
<% elsif col_type == :string
|
1706
|
-
if model.respond_to?(:enumerized_attributes) && (attr = model.enumerized_attributes[k])&.options.present?
|
1707
|
-
enum_html_options = attr.kind_of?(Enumerize::Multiple) ? html_options.merge({ multiple: true, size: (opts = attr.options)&.length + 1 }) : html_options %>
|
1708
|
-
<%= f.select(k.to_sym, [[\"(No #\{k} chosen)\", '^^^brick_NULL^^^']] + opts, { value: val || '^^^brick_NULL^^^' }, enum_html_options) %><%
|
1709
|
-
else %>
|
1710
|
-
<%= f.text_field(k.to_sym, html_options) %><%
|
1711
|
-
end
|
1712
|
-
else
|
1713
|
-
is_includes_text = true %>
|
1714
|
-
<%= f.hidden_field(k.to_sym, html_options) %>
|
1715
|
-
<trix-editor input=\"<%= f.field_id(k) %>\"></trix-editor>
|
1716
|
-
<% end %>
|
1717
|
-
<% when :boolean %>
|
1718
|
-
<%= f.check_box k.to_sym %>
|
1719
|
-
<% when :integer, :decimal, :float %>
|
1720
|
-
<%= digit_pattern = col_type == :integer ? '\\d*' : '\\d*(?:\\.\\d*|)'
|
1721
|
-
# Used to do this for float / decimal: f.number_field k.to_sym
|
1722
|
-
f.text_field k.to_sym, { pattern: digit_pattern, class: 'check-validity' } %>
|
1723
|
-
<% when *dt_pickers.keys
|
1724
|
-
is_includes_dates = true %>
|
1725
|
-
<%= f.text_field k.to_sym, { class: dt_pickers[col_type] } %>
|
1726
|
-
<% when :uuid
|
1727
|
-
is_revert = false %>
|
1728
|
-
<%=
|
1729
|
-
# Postgres naturally uses the +uuid_generate_v4()+ function from the uuid-ossp extension
|
1730
|
-
# If it's not yet enabled then: create extension \"uuid-ossp\";
|
1731
|
-
# ActiveUUID gem created a new :uuid type
|
1732
|
-
val %>
|
1733
|
-
<% when :ltree %>
|
1734
|
-
<%=
|
1735
|
-
# In Postgres labels of data stored in a hierarchical tree-like structure
|
1736
|
-
# If it's not yet enabled then: create extension ltree;
|
1737
|
-
val %>
|
1738
|
-
<% when :binary %>
|
1739
|
-
<%= is_revert = false
|
1740
|
-
if val
|
1741
|
-
# %%% This same kind of geography check is done two other times above ... would be great to DRY it up.
|
1742
|
-
if val.length < 31 && (val.length - 6) % 8 == 0 && val[0..5].bytes == [230, 16, 0, 0, 1, 12]
|
1743
|
-
display_value('geography', val)
|
1744
|
-
else
|
1745
|
-
::Brick::Rails.display_binary(val)
|
1746
|
-
end.html_safe
|
1747
|
-
end %>
|
1748
|
-
<% when :primary_key
|
1749
|
-
is_revert = false %>
|
1750
|
-
<% when :json
|
1751
|
-
is_includes_json = true
|
1752
|
-
if val.is_a?(String)
|
1753
|
-
val_str = val
|
1754
|
-
else
|
1755
|
-
eheij = ActiveSupport::JSON::Encoding.escape_html_entities_in_json
|
1756
|
-
ActiveSupport::JSON::Encoding.escape_html_entities_in_json = false if eheij
|
1757
|
-
val_str = val.to_json
|
1758
|
-
ActiveSupport::JSON::Encoding.escape_html_entities_in_json = eheij
|
1759
|
-
end %>
|
1760
|
-
<%= # Because there are so danged many quotes in JSON, escape them specially by converting to backticks.
|
1761
|
-
# (and previous to this, escape backticks with our own goofy code of ^^br_btick__ )
|
1762
|
-
json_field = f.hidden_field k.to_sym, { class: 'jsonpicker', value: val_str.gsub('`', '^^br_btick__').tr('\"', '`').html_safe } %>
|
1763
|
-
<div id=\"_br_json_<%= f.field_id(k) %>\"></div>
|
1764
|
-
<% else %>
|
1765
|
-
<%= is_revert = false
|
1766
|
-
display_value(col_type, val).html_safe %>
|
1767
|
-
<% end
|
1768
|
-
end
|
1769
|
-
if is_revert
|
1770
|
-
%></td>
|
1771
|
-
<td><svg class=\"revert\" width=\"1.5em\" viewBox=\"0 0 512 512\"><use xlink:href=\"#revertPath\" /></svg>
|
1772
|
-
<% end %>
|
1773
|
-
</td></tr></table>
|
1613
|
+
<%= f.brick_field(k, html_options = {}, val, col, bt, bt_class, bt_name, bt_pair) %>
|
1774
1614
|
</td>
|
1775
1615
|
</tr>
|
1776
1616
|
<% end
|
@@ -1799,11 +1639,12 @@ end
|
|
1799
1639
|
# with a .where(). And the polymorphic class name it points to is the base class name of
|
1800
1640
|
# the STI model instead of its subclass.
|
1801
1641
|
poly_type = #{poly_type.inspect}
|
1802
|
-
|
1642
|
+
#{ (inh_col = @_brick_model.inheritance_column).present? &&
|
1643
|
+
" if poly_type && @#{obj_name}.respond_to?(:#{inh_col}) &&
|
1803
1644
|
(base_type = collection.where_values_hash[poly_type])
|
1804
|
-
collection = collection.rewhere(poly_type => [base_type, @#{obj_name}.#{
|
1805
|
-
end"
|
1806
|
-
|
1645
|
+
collection = collection.rewhere(poly_type => [base_type, @#{obj_name}.#{inh_col}])
|
1646
|
+
end"}"
|
1647
|
+
end
|
1807
1648
|
s << "<table id=\"#{hm_name}\" class=\"shadow\">
|
1808
1649
|
<tr><th>#{hm[1]}#{' poly' if hm[0].options[:as]} #{hm[3]}</th></tr>
|
1809
1650
|
<% collection = @#{obj_name}.#{hm_name}
|
@@ -1844,7 +1685,7 @@ end}
|
|
1844
1685
|
end
|
1845
1686
|
unless is_crosstab
|
1846
1687
|
inline << "
|
1847
|
-
<% if
|
1688
|
+
<% if @_date_fields_present %>
|
1848
1689
|
<link rel=\"stylesheet\" type=\"text/css\" href=\"https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css\">
|
1849
1690
|
<style>
|
1850
1691
|
.flatpickr-calendar {
|
@@ -1859,18 +1700,18 @@ flatpickr(\".timepicker\", {enableTime: true, noCalendar: true});
|
|
1859
1700
|
</script>
|
1860
1701
|
<% end %>
|
1861
1702
|
|
1862
|
-
<% if false #
|
1703
|
+
<% if false # @_dropdown_fields_present %>
|
1863
1704
|
<script src=\"https://cdnjs.cloudflare.com/ajax/libs/slim-select/1.27.1/slimselect.min.js\"></script>
|
1864
1705
|
<link rel=\"stylesheet\" type=\"text/css\" href=\"https://cdnjs.cloudflare.com/ajax/libs/slim-select/1.27.1/slimselect.min.css\">
|
1865
1706
|
<% end %>
|
1866
1707
|
|
1867
|
-
<% if
|
1708
|
+
<% if @_text_fields_present %>
|
1868
1709
|
<script src=\"https://cdn.jsdelivr.net/npm/trix@2.0/dist/trix.umd.min.js\"></script>
|
1869
1710
|
<link rel=\"stylesheet\" type=\"text/css\" href=\"https://cdn.jsdelivr.net/npm/trix@2.0/dist/trix.min.css\">
|
1870
1711
|
<% end %>
|
1871
1712
|
|
1872
1713
|
<% # Started with v0.14.4 of vanilla-jsoneditor
|
1873
|
-
if
|
1714
|
+
if @_json_fields_present %>
|
1874
1715
|
<link rel=\"stylesheet\" type=\"text/css\" href=\"https://cdn.jsdelivr.net/npm/vanilla-jsoneditor/themes/jse-theme-default.min.css\">
|
1875
1716
|
<script type=\"module\">
|
1876
1717
|
import { JSONEditor } from \"https://cdn.jsdelivr.net/npm/vanilla-jsoneditor/index.min.js\";
|
@@ -0,0 +1,187 @@
|
|
1
|
+
module Brick::Rails::FormBuilder
|
2
|
+
DT_PICKERS = { datetime: 'datetimepicker', timestamp: 'datetimepicker', time: 'timepicker', date: 'datepicker' }
|
3
|
+
|
4
|
+
# When this field is one of the appropriate types, will set one of these instance variables accordingly:
|
5
|
+
# @_text_fields_present - To include trix editor
|
6
|
+
# @_date_fields_present - To include flatpickr date / time editor
|
7
|
+
# @_json_fields_present - To include JSONEditor
|
8
|
+
def brick_field(method, html_options = {}, val = nil, col = nil,
|
9
|
+
bt = nil, bt_class = nil, bt_name = nil, bt_pair = nil)
|
10
|
+
model = self.object.class
|
11
|
+
col ||= model.columns_hash[method]
|
12
|
+
out = +'<table><tr><td>'
|
13
|
+
html_options[:class] = 'dimmed' unless val
|
14
|
+
is_revert = true
|
15
|
+
template = instance_variable_get(:@template)
|
16
|
+
if bt
|
17
|
+
bt_class ||= bt[1].first.first
|
18
|
+
bt_name ||= bt[1].map { |x| x.first.name }.join('/')
|
19
|
+
bt_pair ||= bt[1].first
|
20
|
+
|
21
|
+
html_options[:prompt] = "Select #{bt_name}"
|
22
|
+
out << self.select(method.to_sym, bt[3], { value: val || '^^^brick_NULL^^^' }, html_options)
|
23
|
+
bt_link = if (bt_obj = bt_class&.find_by(bt_pair[1] => val))
|
24
|
+
bt_path = template.send(
|
25
|
+
"#{bt_class.base_class._brick_index(:singular)}_path".to_sym,
|
26
|
+
bt_obj.send(bt_class.primary_key.to_sym)
|
27
|
+
)
|
28
|
+
template.link_to('⇛', bt_path, { class: 'show-arrow' })
|
29
|
+
elsif val
|
30
|
+
"<span class=\"orphan\">Orphaned ID: #{val}</span>".html_safe
|
31
|
+
end
|
32
|
+
out << bt_link if bt_link
|
33
|
+
elsif @_brick_monetized_attributes&.include?(method)
|
34
|
+
out << self.text_field(method.to_sym, html_options.merge({ value: Money.new(val.to_i).format }))
|
35
|
+
else
|
36
|
+
col_type = if model.json_column?(col) || val.is_a?(Array)
|
37
|
+
:json
|
38
|
+
elsif col&.sql_type == 'geography'
|
39
|
+
col.sql_type
|
40
|
+
else
|
41
|
+
col&.type
|
42
|
+
end
|
43
|
+
case (col_type ||= col&.sql_type)
|
44
|
+
when :string, :text
|
45
|
+
if ::Brick::Rails::FormBuilder.is_bcrypt?(val) # || .readonly?
|
46
|
+
is_revert = false
|
47
|
+
out << ::Brick::Rails::FormBuilder.hide_bcrypt(val, nil, 1000)
|
48
|
+
elsif col_type == :string
|
49
|
+
if model.respond_to?(:enumerized_attributes) && (opts = (attr = model.enumerized_attributes[method])&.options).present?
|
50
|
+
enum_html_options = attr.kind_of?(Enumerize::Multiple) ? html_options.merge({ multiple: true, size: opts.length + 1 }) : html_options
|
51
|
+
out << self.select(method.to_sym, [["(No #{method} chosen)", '^^^brick_NULL^^^']] + opts, { value: val || '^^^brick_NULL^^^' }, enum_html_options)
|
52
|
+
else
|
53
|
+
out << self.text_field(method.to_sym, html_options)
|
54
|
+
end
|
55
|
+
else
|
56
|
+
template.instance_variable_set(:@_text_fields_present, true)
|
57
|
+
out << self.hidden_field(method.to_sym, html_options)
|
58
|
+
out << "<trix-editor input=\"#{self.field_id(method)}\"></trix-editor>"
|
59
|
+
end
|
60
|
+
when :boolean
|
61
|
+
out << self.check_box(method.to_sym)
|
62
|
+
when :integer, :decimal, :float
|
63
|
+
digit_pattern = col_type == :integer ? '\d*' : '\d*(?:\.\d*|)'
|
64
|
+
# Used to do this for float / decimal: self.number_field method.to_sym
|
65
|
+
out << self.text_field(method.to_sym, { pattern: digit_pattern, class: 'check-validity' })
|
66
|
+
when *DT_PICKERS.keys
|
67
|
+
template.instance_variable_set(:@_date_fields_present, true)
|
68
|
+
out << self.text_field(method.to_sym, { class: DT_PICKERS[col_type] })
|
69
|
+
when :uuid
|
70
|
+
is_revert = false
|
71
|
+
# Postgres naturally uses the +uuid_generate_v4()+ function from the uuid-ossp extension
|
72
|
+
# If it's not yet enabled then: create extension \"uuid-ossp\";
|
73
|
+
# ActiveUUID gem created a new :uuid type
|
74
|
+
out << val
|
75
|
+
when :ltree
|
76
|
+
# In Postgres labels of data stored in a hierarchical tree-like structure
|
77
|
+
# If it's not yet enabled then: create extension ltree;
|
78
|
+
out << val
|
79
|
+
when :binary
|
80
|
+
is_revert = false
|
81
|
+
if val
|
82
|
+
# %%% This same kind of geography check is done two other times in engine.rb ... would be great to DRY it up.
|
83
|
+
out << if val.length < 31 && (val.length - 6) % 8 == 0 && val[0..5].bytes == [230, 16, 0, 0, 1, 12]
|
84
|
+
::Brick::Rails.display_value('geography', val)
|
85
|
+
else
|
86
|
+
::Brick::Rails.display_binary(val)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
when :primary_key
|
90
|
+
is_revert = false
|
91
|
+
when :json
|
92
|
+
template.instance_variable_set(:@_json_fields_present, true)
|
93
|
+
if val.is_a?(String)
|
94
|
+
val_str = val
|
95
|
+
else
|
96
|
+
eheij = ActiveSupport::JSON::Encoding.escape_html_entities_in_json
|
97
|
+
ActiveSupport::JSON::Encoding.escape_html_entities_in_json = false if eheij
|
98
|
+
val_str = val.to_json
|
99
|
+
ActiveSupport::JSON::Encoding.escape_html_entities_in_json = eheij
|
100
|
+
end
|
101
|
+
# Because there are so danged many quotes in JSON, escape them specially by converting to backticks.
|
102
|
+
# (and previous to this, escape backticks with our own goofy code of ^^br_btick__ )
|
103
|
+
out << (json_field = self.hidden_field(method.to_sym, { class: 'jsonpicker', value: val_str.gsub('`', '^^br_btick__').tr('\"', '`').html_safe }))
|
104
|
+
out << "<div id=\"_br_json_#{self.field_id(method)}\"></div>"
|
105
|
+
else
|
106
|
+
is_revert = false
|
107
|
+
out << ::Brick::Rails.display_value(col_type, val).html_safe
|
108
|
+
end
|
109
|
+
end
|
110
|
+
if is_revert
|
111
|
+
out << "</td>
|
112
|
+
"
|
113
|
+
out << '<td><svg class="revert" width="1.5em" viewBox="0 0 512 512"><use xlink:href="#revertPath" /></svg>'
|
114
|
+
end
|
115
|
+
out << "</td></tr></table>
|
116
|
+
"
|
117
|
+
out.html_safe
|
118
|
+
end # brick_field
|
119
|
+
|
120
|
+
# --- CLASS METHODS ---
|
121
|
+
|
122
|
+
def self.is_bcrypt?(val)
|
123
|
+
val.is_a?(String) && val.length == 60 && val.start_with?('$2a$')
|
124
|
+
end
|
125
|
+
|
126
|
+
def self.hide_bcrypt(val, is_xml = nil, max_len = 200)
|
127
|
+
if ::Brick::Rails::FormBuilder.is_bcrypt?(val)
|
128
|
+
'(hidden)'
|
129
|
+
else
|
130
|
+
if val.is_a?(String)
|
131
|
+
val = val.dup.force_encoding('UTF-8').strip
|
132
|
+
return CGI.escapeHTML(val) if is_xml
|
133
|
+
|
134
|
+
if val.length > max_len
|
135
|
+
if val[0] == '<' # Seems to be HTML?
|
136
|
+
cur_len = 0
|
137
|
+
cur_idx = 0
|
138
|
+
# Find which HTML tags we might be inside so we can apply ending tags to balance
|
139
|
+
element_name = nil
|
140
|
+
in_closing = nil
|
141
|
+
elements = []
|
142
|
+
val.each_char do |ch|
|
143
|
+
case ch
|
144
|
+
when '<'
|
145
|
+
element_name = +''
|
146
|
+
when '/' # First character of tag is '/'?
|
147
|
+
in_closing = true if element_name == ''
|
148
|
+
when '>'
|
149
|
+
if element_name
|
150
|
+
if in_closing
|
151
|
+
if (idx = elements.index { |tag| tag.downcase == element_name.downcase })
|
152
|
+
elements.delete_at(idx)
|
153
|
+
end
|
154
|
+
elsif (tag_name = element_name.split.first).present?
|
155
|
+
elements.unshift(tag_name)
|
156
|
+
end
|
157
|
+
element_name = nil
|
158
|
+
in_closing = nil
|
159
|
+
end
|
160
|
+
else
|
161
|
+
element_name << ch if element_name
|
162
|
+
end
|
163
|
+
cur_idx += 1
|
164
|
+
# Unless it's inside wickets then this is real text content, and see if we're at the limit
|
165
|
+
break if element_name.nil? && ((cur_len += 1) > max_len)
|
166
|
+
end
|
167
|
+
val = val[0..cur_idx]
|
168
|
+
# Somehow still in the middle of an opening tag right at the end? (Should never happen)
|
169
|
+
if !in_closing && (tag_name = element_name&.split&.first)&.present?
|
170
|
+
elements.unshift(tag_name)
|
171
|
+
val << '>'
|
172
|
+
end
|
173
|
+
elements.each do |closing_tag|
|
174
|
+
val << "</#{closing_tag}>"
|
175
|
+
end
|
176
|
+
else # Not HTML, just cut it at the length
|
177
|
+
val = val[0...max_len]
|
178
|
+
end
|
179
|
+
val = "#{val}..."
|
180
|
+
end
|
181
|
+
val
|
182
|
+
else
|
183
|
+
val.to_s
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
@@ -133,7 +133,7 @@ module Brick::Rails::FormTags
|
|
133
133
|
val ? Money.new(val.to_i).format : ''
|
134
134
|
else
|
135
135
|
col_type = col&.sql_type == 'geography' ? col.sql_type : col&.type
|
136
|
-
display_value(col_type || col&.sql_type, val).to_s
|
136
|
+
::Brick::Rails.display_value(col_type || col&.sql_type, val).to_s
|
137
137
|
end
|
138
138
|
elsif cust_col
|
139
139
|
data = cust_col.first.map { |cc_part| obj.send(cc_part.last) }
|
data/lib/brick/version_number.rb
CHANGED
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.127
|
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-04-
|
11
|
+
date: 2023-04-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -244,6 +244,7 @@ files:
|
|
244
244
|
- lib/brick/frameworks/rails/controller.rb
|
245
245
|
- lib/brick/frameworks/rails/crosstab.brk
|
246
246
|
- lib/brick/frameworks/rails/engine.rb
|
247
|
+
- lib/brick/frameworks/rails/form_builder.rb
|
247
248
|
- lib/brick/frameworks/rails/form_tags.rb
|
248
249
|
- lib/brick/frameworks/rspec.rb
|
249
250
|
- lib/brick/join_array.rb
|
@@ -270,7 +271,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
270
271
|
requirements:
|
271
272
|
- - ">="
|
272
273
|
- !ruby/object:Gem::Version
|
273
|
-
version: 2.3.
|
274
|
+
version: 2.3.8
|
274
275
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
275
276
|
requirements:
|
276
277
|
- - ">="
|