brick 1.0.125 → 1.0.126
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/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 +185 -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: b59690045d31108dece3222f655503a771ab860697993459a6beb92aa0ecdb07
|
4
|
+
data.tar.gz: 4c83d54ddc01e03330ac82f5949cece3f21631624adb704b923bd338ac84481c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c12e4073de8230683825617fccabeeda71746dcf3c892a60557990777543c15a3e9a18a8c7bdcf3b1c236bf422ec74d10b98bf1341b5d472e611799c8e74de31
|
7
|
+
data.tar.gz: 6e9fdb9e41ff12a1b5092226133cb7c0d8444bf330e2557da156bc7f21d4377678061bd65c5b36ad3b9d1f9bf88203594c34cf8bcaabad7b93c2609b2798e474
|
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,185 @@
|
|
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, bt = nil, bt_class = nil, bt_name = nil, bt_pair = nil)
|
9
|
+
model = self.object.class
|
10
|
+
col ||= model.columns_hash[method]
|
11
|
+
out = +'<table><tr><td>'
|
12
|
+
html_options[:class] = 'dimmed' unless val
|
13
|
+
is_revert = true
|
14
|
+
template = instance_variable_get(:@template)
|
15
|
+
if bt
|
16
|
+
bt_class ||= bt[1].first.first
|
17
|
+
bt_name ||= bt[1].map { |x| x.first.name }.join('/')
|
18
|
+
bt_pair ||= bt[1].first
|
19
|
+
|
20
|
+
html_options[:prompt] = "Select #{bt_name}"
|
21
|
+
out << self.select(method.to_sym, bt[3], { value: val || '^^^brick_NULL^^^' }, html_options)
|
22
|
+
out << if (bt_obj = bt_class&.find_by(bt_pair[1] => val))
|
23
|
+
bt_path = template.send(
|
24
|
+
"#{bt_class.base_class._brick_index(:singular)}_path".to_sym,
|
25
|
+
bt_obj.send(bt_class.primary_key.to_sym)
|
26
|
+
)
|
27
|
+
template.link_to('⇛', bt_path, { class: 'show-arrow' })
|
28
|
+
elsif val
|
29
|
+
"<span class=\"orphan\">Orphaned ID: #{val}</span>".html_safe
|
30
|
+
end
|
31
|
+
elsif @_brick_monetized_attributes&.include?(method)
|
32
|
+
out << self.text_field(method.to_sym, html_options.merge({ value: Money.new(val.to_i).format }))
|
33
|
+
else
|
34
|
+
col_type = if model.json_column?(col) || val.is_a?(Array)
|
35
|
+
:json
|
36
|
+
elsif col&.sql_type == 'geography'
|
37
|
+
col.sql_type
|
38
|
+
else
|
39
|
+
col&.type
|
40
|
+
end
|
41
|
+
case (col_type ||= col&.sql_type)
|
42
|
+
when :string, :text
|
43
|
+
if ::Brick::Rails::FormBuilder.is_bcrypt?(val) # || .readonly?
|
44
|
+
is_revert = false
|
45
|
+
out << ::Brick::Rails::FormBuilder.hide_bcrypt(val, nil, 1000)
|
46
|
+
elsif col_type == :string
|
47
|
+
if model.respond_to?(:enumerized_attributes) && (opts = (attr = model.enumerized_attributes[method])&.options).present?
|
48
|
+
enum_html_options = attr.kind_of?(Enumerize::Multiple) ? html_options.merge({ multiple: true, size: opts.length + 1 }) : html_options
|
49
|
+
out << self.select(method.to_sym, [["(No #{method} chosen)", '^^^brick_NULL^^^']] + opts, { value: val || '^^^brick_NULL^^^' }, enum_html_options)
|
50
|
+
else
|
51
|
+
out << self.text_field(method.to_sym, html_options)
|
52
|
+
end
|
53
|
+
else
|
54
|
+
template.instance_variable_set(:@_text_fields_present, true)
|
55
|
+
out << self.hidden_field(method.to_sym, html_options)
|
56
|
+
out << "<trix-editor input=\"#{self.field_id(method)}\"></trix-editor>"
|
57
|
+
end
|
58
|
+
when :boolean
|
59
|
+
out << self.check_box(method.to_sym)
|
60
|
+
when :integer, :decimal, :float
|
61
|
+
digit_pattern = col_type == :integer ? '\d*' : '\d*(?:\.\d*|)'
|
62
|
+
# Used to do this for float / decimal: self.number_field method.to_sym
|
63
|
+
out << self.text_field(method.to_sym, { pattern: digit_pattern, class: 'check-validity' })
|
64
|
+
when *DT_PICKERS.keys
|
65
|
+
template.instance_variable_set(:@_date_fields_present, true)
|
66
|
+
out << self.text_field(method.to_sym, { class: DT_PICKERS[col_type] })
|
67
|
+
when :uuid
|
68
|
+
is_revert = false
|
69
|
+
# Postgres naturally uses the +uuid_generate_v4()+ function from the uuid-ossp extension
|
70
|
+
# If it's not yet enabled then: create extension \"uuid-ossp\";
|
71
|
+
# ActiveUUID gem created a new :uuid type
|
72
|
+
out << val
|
73
|
+
when :ltree
|
74
|
+
# In Postgres labels of data stored in a hierarchical tree-like structure
|
75
|
+
# If it's not yet enabled then: create extension ltree;
|
76
|
+
out << val
|
77
|
+
when :binary
|
78
|
+
is_revert = false
|
79
|
+
if val
|
80
|
+
# %%% This same kind of geography check is done two other times in engine.rb ... would be great to DRY it up.
|
81
|
+
out << if val.length < 31 && (val.length - 6) % 8 == 0 && val[0..5].bytes == [230, 16, 0, 0, 1, 12]
|
82
|
+
::Brick::Rails.display_value('geography', val)
|
83
|
+
else
|
84
|
+
::Brick::Rails.display_binary(val)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
when :primary_key
|
88
|
+
is_revert = false
|
89
|
+
when :json
|
90
|
+
template.instance_variable_set(:@_json_fields_present, true)
|
91
|
+
if val.is_a?(String)
|
92
|
+
val_str = val
|
93
|
+
else
|
94
|
+
eheij = ActiveSupport::JSON::Encoding.escape_html_entities_in_json
|
95
|
+
ActiveSupport::JSON::Encoding.escape_html_entities_in_json = false if eheij
|
96
|
+
val_str = val.to_json
|
97
|
+
ActiveSupport::JSON::Encoding.escape_html_entities_in_json = eheij
|
98
|
+
end
|
99
|
+
# Because there are so danged many quotes in JSON, escape them specially by converting to backticks.
|
100
|
+
# (and previous to this, escape backticks with our own goofy code of ^^br_btick__ )
|
101
|
+
out << (json_field = self.hidden_field(method.to_sym, { class: 'jsonpicker', value: val_str.gsub('`', '^^br_btick__').tr('\"', '`').html_safe }))
|
102
|
+
out << "<div id=\"_br_json_#{self.field_id(method)}\"></div>"
|
103
|
+
else
|
104
|
+
is_revert = false
|
105
|
+
out << ::Brick::Rails.display_value(col_type, val).html_safe
|
106
|
+
end
|
107
|
+
end
|
108
|
+
if is_revert
|
109
|
+
out << "</td>
|
110
|
+
"
|
111
|
+
out << '<td><svg class="revert" width="1.5em" viewBox="0 0 512 512"><use xlink:href="#revertPath" /></svg>'
|
112
|
+
end
|
113
|
+
out << "</td></tr></table>
|
114
|
+
"
|
115
|
+
out.html_safe
|
116
|
+
end # brick_field
|
117
|
+
|
118
|
+
# --- CLASS METHODS ---
|
119
|
+
|
120
|
+
def self.is_bcrypt?(val)
|
121
|
+
val.is_a?(String) && val.length == 60 && val.start_with?('$2a$')
|
122
|
+
end
|
123
|
+
|
124
|
+
def self.hide_bcrypt(val, is_xml = nil, max_len = 200)
|
125
|
+
if ::Brick::Rails::FormBuilder.is_bcrypt?(val)
|
126
|
+
'(hidden)'
|
127
|
+
else
|
128
|
+
if val.is_a?(String)
|
129
|
+
val = val.dup.force_encoding('UTF-8').strip
|
130
|
+
return CGI.escapeHTML(val) if is_xml
|
131
|
+
|
132
|
+
if val.length > max_len
|
133
|
+
if val[0] == '<' # Seems to be HTML?
|
134
|
+
cur_len = 0
|
135
|
+
cur_idx = 0
|
136
|
+
# Find which HTML tags we might be inside so we can apply ending tags to balance
|
137
|
+
element_name = nil
|
138
|
+
in_closing = nil
|
139
|
+
elements = []
|
140
|
+
val.each_char do |ch|
|
141
|
+
case ch
|
142
|
+
when '<'
|
143
|
+
element_name = +''
|
144
|
+
when '/' # First character of tag is '/'?
|
145
|
+
in_closing = true if element_name == ''
|
146
|
+
when '>'
|
147
|
+
if element_name
|
148
|
+
if in_closing
|
149
|
+
if (idx = elements.index { |tag| tag.downcase == element_name.downcase })
|
150
|
+
elements.delete_at(idx)
|
151
|
+
end
|
152
|
+
elsif (tag_name = element_name.split.first).present?
|
153
|
+
elements.unshift(tag_name)
|
154
|
+
end
|
155
|
+
element_name = nil
|
156
|
+
in_closing = nil
|
157
|
+
end
|
158
|
+
else
|
159
|
+
element_name << ch if element_name
|
160
|
+
end
|
161
|
+
cur_idx += 1
|
162
|
+
# Unless it's inside wickets then this is real text content, and see if we're at the limit
|
163
|
+
break if element_name.nil? && ((cur_len += 1) > max_len)
|
164
|
+
end
|
165
|
+
val = val[0..cur_idx]
|
166
|
+
# Somehow still in the middle of an opening tag right at the end? (Should never happen)
|
167
|
+
if !in_closing && (tag_name = element_name&.split&.first)&.present?
|
168
|
+
elements.unshift(tag_name)
|
169
|
+
val << '>'
|
170
|
+
end
|
171
|
+
elements.each do |closing_tag|
|
172
|
+
val << "</#{closing_tag}>"
|
173
|
+
end
|
174
|
+
else # Not HTML, just cut it at the length
|
175
|
+
val = val[0...max_len]
|
176
|
+
end
|
177
|
+
val = "#{val}..."
|
178
|
+
end
|
179
|
+
val
|
180
|
+
else
|
181
|
+
val.to_s
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
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.126
|
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
|
- - ">="
|