brick 1.0.210 → 1.0.212
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/config.rb +26 -1
- data/lib/brick/extensions.rb +92 -19
- data/lib/brick/frameworks/rails/engine.rb +31 -8
- data/lib/brick/frameworks/rails/form_builder.rb +36 -1
- data/lib/brick/frameworks/rails/form_tags.rb +194 -31
- data/lib/brick/frameworks/rails.rb +12 -1
- data/lib/brick/route_mapper.rb +9 -0
- data/lib/brick/version_number.rb +1 -1
- data/lib/generators/brick/install_generator.rb +16 -0
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3e954e525ea7a17eea2b33a125283f8af47a7bad1e457780815a8f53e06ed8fc
|
|
4
|
+
data.tar.gz: 9ded8bfa75d407294eb3e34895d1fc36ffa17767b9cbdeee0c961d6d9e821653
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6c2d33f2a6247cc001071929731d2b2543d2b91ba0e8c22afeda7d9fa40e37ae9c3957d4046f8157a34b1549dca8e542de97a58f22b25a312532eed775d3989c
|
|
7
|
+
data.tar.gz: 4e63b7986eb7b683421ef92d00fe61a3970ed0d24fb57403a89d05c114760ad00310e6c635d66bc0388e5ca26b6c6fd2061574c83e1f70b60f90baa22babcb92
|
data/lib/brick/config.rb
CHANGED
|
@@ -238,7 +238,24 @@ module Brick
|
|
|
238
238
|
end
|
|
239
239
|
|
|
240
240
|
def treat_as_associative=(tables)
|
|
241
|
-
@mutex.synchronize
|
|
241
|
+
@mutex.synchronize do
|
|
242
|
+
@treat_as_associative = if tables.is_a?(Hash)
|
|
243
|
+
tables.each_with_object({}) do |v, s|
|
|
244
|
+
# If it's :constellation, or anything else in a hash, we'll take its value
|
|
245
|
+
# (and hopefully in this case that would be either a string or nil)
|
|
246
|
+
dsl = ((v.last.is_a?(Symbol) && v.last) || v.last&.values&.last)
|
|
247
|
+
unless (dsl ||= '').is_a?(String) || dsl.is_a?(Symbol)
|
|
248
|
+
puts "Was really expecting #{v.first} / #{v.last.first&.first} / #{dsl} to be a string, " +
|
|
249
|
+
"so will disregard #{dsl} and just turn on simple constellation view for #{v.first}."
|
|
250
|
+
end
|
|
251
|
+
s[v.first] = v.last.is_a?(Hash) ? dsl : v.last
|
|
252
|
+
end
|
|
253
|
+
elsif tables.is_a?(String) # comma-separated list?
|
|
254
|
+
tables.split(',').each_with_object({}) { |v, s| s[v.trim] = nil }
|
|
255
|
+
else # Expecting an Array, and have no special presentation
|
|
256
|
+
tables&.each_with_object({}) { |v, s| s[v] = nil }
|
|
257
|
+
end
|
|
258
|
+
end
|
|
242
259
|
end
|
|
243
260
|
|
|
244
261
|
# Polymorphic associations
|
|
@@ -286,6 +303,14 @@ module Brick
|
|
|
286
303
|
@mutex.synchronize { @model_descrips = descrips }
|
|
287
304
|
end
|
|
288
305
|
|
|
306
|
+
def erd_show_columns
|
|
307
|
+
@mutex.synchronize { @erd_show_columns ||= [] }
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
def erd_show_columns=(descrips)
|
|
311
|
+
@mutex.synchronize { @erd_show_columns = descrips }
|
|
312
|
+
end
|
|
313
|
+
|
|
289
314
|
def sti_namespace_prefixes
|
|
290
315
|
@mutex.synchronize { @sti_namespace_prefixes ||= {} }
|
|
291
316
|
end
|
data/lib/brick/extensions.rb
CHANGED
|
@@ -92,11 +92,49 @@ module ActiveRecord
|
|
|
92
92
|
reflect_on_association(assoc).foreign_type || "#{assoc}_type"
|
|
93
93
|
end
|
|
94
94
|
|
|
95
|
-
def _brick_all_fields
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
95
|
+
def _brick_all_fields(skip_id = nil)
|
|
96
|
+
col_names = columns_hash.keys
|
|
97
|
+
# If it's a composite primary key then allow all the values through
|
|
98
|
+
# TODO: Should disallow any autoincrement / SERIAL columns
|
|
99
|
+
if skip_id && (pk_as_array = _pk_as_array).length == 1
|
|
100
|
+
col_names -= _pk_as_array
|
|
101
|
+
end
|
|
102
|
+
hoa, hma, rtans = _activestorage_actiontext_fields
|
|
103
|
+
col_names.map(&:to_sym) + hoa + hma.map { |as| { as => [] } } + rtans.values
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Return three lists of fields for this model --
|
|
107
|
+
# has_one_attached, has_many_attached, and has_rich_text
|
|
108
|
+
def _activestorage_actiontext_fields
|
|
109
|
+
fields = [[], [], {}]
|
|
110
|
+
if Object.const_defined?('ActiveStorage') && respond_to?(:generated_association_methods) && !(self <= ::ActiveStorage::Blob) # ActiveStorage
|
|
111
|
+
generated_association_methods.instance_methods.each do |method_sym|
|
|
112
|
+
method_str = method_sym.to_s
|
|
113
|
+
fields[0] << method_str[0..-13].to_sym if method_str.end_with?('_attachment=') # has_one_attached
|
|
114
|
+
fields[1] << method_str[0..-14].to_sym if method_str.end_with?('_attachments=') # has_many_attached
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
if respond_to?(:rich_text_association_names) # ActionText
|
|
118
|
+
rich_text_association_names&.each do |rtan| # has_rich_text
|
|
119
|
+
rtan_str = rtan.to_s
|
|
120
|
+
fields[2][rtan] = rtan_str.start_with?('rich_text_') ? rtan_str[10..-1].to_sym : rtan
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
fields
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def _active_storage_name(col_name)
|
|
127
|
+
if Object.const_defined?('ActiveStorage') && (self <= ::ActiveStorage::Attachment || self <= ::ActiveStorage::Blob)
|
|
128
|
+
if (col_str = col_name.to_s).end_with?('_attachments')
|
|
129
|
+
col_str[0..-13]
|
|
130
|
+
elsif col_str.end_with?('_blobs')
|
|
131
|
+
col_str[0..-7]
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def _pk_as_array
|
|
137
|
+
self.primary_key.is_a?(Array) ? self.primary_key : [self.primary_key]
|
|
100
138
|
end
|
|
101
139
|
|
|
102
140
|
def _br_quoted_name(name)
|
|
@@ -147,8 +185,8 @@ module ActiveRecord
|
|
|
147
185
|
skip_columns = _brick_get_fks + (::Brick.config.metadata_columns || []) + [primary_key]
|
|
148
186
|
dsl = if (descrip_col = columns.find { |c| [:boolean, :binary, :xml].exclude?(c.type) && skip_columns.exclude?(c.name) })
|
|
149
187
|
"[#{descrip_col.name}]"
|
|
150
|
-
|
|
151
|
-
"#{name} ##{
|
|
188
|
+
else
|
|
189
|
+
"#{name} ##{_pk_as_array.map { |pk_part| "[#{pk_part}]" }.join(', ')}"
|
|
152
190
|
end
|
|
153
191
|
::Brick.config.model_descrips[name] = dsl
|
|
154
192
|
end
|
|
@@ -841,6 +879,8 @@ module ActiveRecord
|
|
|
841
879
|
end
|
|
842
880
|
through_sources.push(src_ref) unless src_ref.belongs_to?
|
|
843
881
|
from_clause = +"#{_br_quoted_name(through_sources.first.table_name)} br_t0"
|
|
882
|
+
# ActiveStorage will not get the correct count unless we do some extra filtering later
|
|
883
|
+
tbl_nm = 'br_t0' if Object.const_defined?('ActiveStorage') && through_sources.first.klass <= ::ActiveStorage::Attachment
|
|
844
884
|
fk_col = through_sources.shift.foreign_key
|
|
845
885
|
|
|
846
886
|
idx = 0
|
|
@@ -934,10 +974,14 @@ module ActiveRecord
|
|
|
934
974
|
tbl_nm = hm.macro == :has_and_belongs_to_many ? hm.join_table : hm.table_name
|
|
935
975
|
hm_table_name = _br_quoted_name(tbl_nm)
|
|
936
976
|
end
|
|
977
|
+
# ActiveStorage has_many_attached needs a bit more filtering
|
|
978
|
+
if (k_str = hm.klass._active_storage_name(k))
|
|
979
|
+
where_ct_clause = "WHERE #{_br_quoted_name("#{tbl_nm}.name")} = '#{k_str}' "
|
|
980
|
+
end
|
|
937
981
|
group_bys = ::Brick.is_oracle || is_mssql ? hm_selects : (1..hm_selects.length).to_a
|
|
938
982
|
join_clause = "LEFT OUTER
|
|
939
983
|
JOIN (SELECT #{hm_selects.map { |s| _br_quoted_name("#{'br_t0.' if from_clause}#{s}") }.join(', ')}, COUNT(#{'DISTINCT ' if hm.options[:through]}#{_br_quoted_name(count_column)
|
|
940
|
-
}) AS c_t_ FROM #{from_clause || hm_table_name} GROUP BY #{group_bys.join(', ')}) #{_br_quoted_name(tbl_alias)}"
|
|
984
|
+
}) AS c_t_ FROM #{from_clause || hm_table_name} #{where_ct_clause}GROUP BY #{group_bys.join(', ')}) #{_br_quoted_name(tbl_alias)}"
|
|
941
985
|
self.joins_values |= ["#{join_clause} ON #{on_clause.join(' AND ')}"] # Same as: joins!(...)
|
|
942
986
|
end unless cust_col_override
|
|
943
987
|
while (n = nix.pop)
|
|
@@ -1025,8 +1069,8 @@ JOIN (SELECT #{hm_selects.map { |s| _br_quoted_name("#{'br_t0.' if from_clause}#
|
|
|
1025
1069
|
end
|
|
1026
1070
|
|
|
1027
1071
|
# ActiveStorage compatibility
|
|
1028
|
-
selects << 'service_name' if klass.name == 'ActiveStorage::Blob' && ActiveStorage::Blob.columns_hash.key?('service_name')
|
|
1029
|
-
selects << 'blob_id' if klass.name == 'ActiveStorage::Attachment' && ActiveStorage::Attachment.columns_hash.key?('blob_id')
|
|
1072
|
+
selects << 'service_name' if klass.name == 'ActiveStorage::Blob' && ::ActiveStorage::Blob.columns_hash.key?('service_name')
|
|
1073
|
+
selects << 'blob_id' if klass.name == 'ActiveStorage::Attachment' && ::ActiveStorage::Attachment.columns_hash.key?('blob_id')
|
|
1030
1074
|
# Pay gem compatibility
|
|
1031
1075
|
selects << 'processor' if klass.name == 'Pay::Customer' && Pay::Customer.columns_hash.key?('processor')
|
|
1032
1076
|
selects << 'customer_id' if klass.name == 'Pay::Subscription' && Pay::Subscription.columns_hash.key?('customer_id')
|
|
@@ -2034,6 +2078,23 @@ class Object
|
|
|
2034
2078
|
# add_csp_hash
|
|
2035
2079
|
# end
|
|
2036
2080
|
# end
|
|
2081
|
+
|
|
2082
|
+
# Associate and unassociate in an N:M relation
|
|
2083
|
+
self.define_method :associate do
|
|
2084
|
+
if (base_class = (model = params['modelName']&.constantize).base_class)
|
|
2085
|
+
args = params['args']
|
|
2086
|
+
record = base_class.create(args[0] => args[1], args[2] => args[3])
|
|
2087
|
+
add_csp_hash
|
|
2088
|
+
render json: { data: record.id }
|
|
2089
|
+
end
|
|
2090
|
+
end
|
|
2091
|
+
self.define_method :unassociate do
|
|
2092
|
+
if (base_class = (model = params['modelName']&.constantize).base_class)
|
|
2093
|
+
base_class.find_by(base_class._pk_as_array&.first => params['id']).delete
|
|
2094
|
+
add_csp_hash
|
|
2095
|
+
end
|
|
2096
|
+
end
|
|
2097
|
+
|
|
2037
2098
|
self.define_method :orphans do
|
|
2038
2099
|
instance_variable_set(:@orphans, ::Brick.find_orphans(::Brick.set_db_schema(params).first))
|
|
2039
2100
|
add_csp_hash
|
|
@@ -2369,6 +2430,8 @@ class Object
|
|
|
2369
2430
|
end
|
|
2370
2431
|
end
|
|
2371
2432
|
|
|
2433
|
+
params_name_sym = (params_name = "#{singular_table_name}_params").to_sym
|
|
2434
|
+
|
|
2372
2435
|
# By default, views get marked as read-only
|
|
2373
2436
|
# unless model.readonly # (relation = relations[model.table_name]).key?(:isView)
|
|
2374
2437
|
code << " def new\n"
|
|
@@ -2376,7 +2439,11 @@ class Object
|
|
|
2376
2439
|
code << " end\n"
|
|
2377
2440
|
self.define_method :new do
|
|
2378
2441
|
_schema, @_is_show_schema_list = ::Brick.set_db_schema(params)
|
|
2379
|
-
new_params =
|
|
2442
|
+
new_params = begin
|
|
2443
|
+
send(params_name_sym)
|
|
2444
|
+
rescue
|
|
2445
|
+
end
|
|
2446
|
+
new_params ||= model.attribute_names.each_with_object({}) do |a, s|
|
|
2380
2447
|
if (val = params["__#{a}"])
|
|
2381
2448
|
# val = case new_obj.class.column_for_attribute(a).type
|
|
2382
2449
|
# when :datetime, :date, :time, :timestamp
|
|
@@ -2390,15 +2457,13 @@ class Object
|
|
|
2390
2457
|
if (new_obj = model.new(new_params)).respond_to?(:serializable_hash)
|
|
2391
2458
|
# Convert any Filename objects with nil into an empty string so that #encode can be called on them
|
|
2392
2459
|
new_obj.serializable_hash.each do |k, v|
|
|
2393
|
-
new_obj.send("#{k}=", ActiveStorage::Filename.new('')) if v.is_a?(ActiveStorage::Filename) && !v.instance_variable_get(:@filename)
|
|
2460
|
+
new_obj.send("#{k}=", ::ActiveStorage::Filename.new('')) if v.is_a?(::ActiveStorage::Filename) && !v.instance_variable_get(:@filename)
|
|
2394
2461
|
end if Object.const_defined?('ActiveStorage')
|
|
2395
2462
|
end
|
|
2396
2463
|
instance_variable_set("@#{singular_table_name}".to_sym, new_obj)
|
|
2397
2464
|
add_csp_hash
|
|
2398
2465
|
end
|
|
2399
2466
|
|
|
2400
|
-
params_name_sym = (params_name = "#{singular_table_name}_params").to_sym
|
|
2401
|
-
|
|
2402
2467
|
code << " def create\n"
|
|
2403
2468
|
code << " @#{singular_table_name} = #{model.name}.create(#{params_name})\n"
|
|
2404
2469
|
code << " end\n"
|
|
@@ -2415,8 +2480,7 @@ class Object
|
|
|
2415
2480
|
end
|
|
2416
2481
|
render json: { result: ::Brick.unexclude_column(table_name, col) }
|
|
2417
2482
|
else
|
|
2418
|
-
|
|
2419
|
-
(created_obj = model.send(:create, send(params_name_sym))))
|
|
2483
|
+
created_obj = model.send(:create, send(params_name_sym))
|
|
2420
2484
|
@_lookup_context.instance_variable_set(:@_brick_model, model)
|
|
2421
2485
|
if created_obj.errors.empty?
|
|
2422
2486
|
index
|
|
@@ -2493,7 +2557,16 @@ class Object
|
|
|
2493
2557
|
if (upd_hash ||= upd_params).fetch(model.inheritance_column, nil)&.strip == ''
|
|
2494
2558
|
upd_hash[model.inheritance_column] = nil
|
|
2495
2559
|
end
|
|
2496
|
-
|
|
2560
|
+
# Do not clear out a has_many_attached field if it already has an entry and nothing is supplied
|
|
2561
|
+
hoa, hma, rtans = model._activestorage_actiontext_fields
|
|
2562
|
+
all_params = params[singular_table_name]
|
|
2563
|
+
hma.each do |hma_field|
|
|
2564
|
+
if upd_hash.fetch(hma_field) == [''] && # No new attachments...
|
|
2565
|
+
all_params&.fetch("_brick_attached_#{hma_field}", nil) # ...and there is something existing
|
|
2566
|
+
upd_hash.delete(hma_field)
|
|
2567
|
+
end
|
|
2568
|
+
end
|
|
2569
|
+
obj.send(:update, upd_hash)
|
|
2497
2570
|
if obj.errors.any? # Surface errors to the user in a flash message
|
|
2498
2571
|
flash.now.alert = (obj.errors.errors.map { |err| "<b>#{err.attribute}</b> #{err.message}" }.join(', '))
|
|
2499
2572
|
end
|
|
@@ -2543,7 +2616,7 @@ class Object
|
|
|
2543
2616
|
|
|
2544
2617
|
if is_need_params
|
|
2545
2618
|
code << " def #{params_name}\n"
|
|
2546
|
-
permits_txt = model._brick_find_permits(model, permits = model._brick_all_fields)
|
|
2619
|
+
permits_txt = model._brick_find_permits(model, permits = model._brick_all_fields(true))
|
|
2547
2620
|
code << " params.require(:#{require_name = model.name.underscore.tr('/', '_')
|
|
2548
2621
|
}).permit(#{permits_txt.map(&:inspect).join(', ')})\n"
|
|
2549
2622
|
code << " end\n"
|
|
@@ -3031,7 +3104,7 @@ module Brick
|
|
|
3031
3104
|
else
|
|
3032
3105
|
res_name = (tbl_name_parts = tbl_name.split('.'))[0..-2].first
|
|
3033
3106
|
res_name << '.' if res_name
|
|
3034
|
-
(res_name ||= +'') << relation&.fetch(:resource, nil) || tbl_name_parts.last
|
|
3107
|
+
(res_name ||= +'') << (relation&.fetch(:resource, nil) || tbl_name_parts.last)
|
|
3035
3108
|
end
|
|
3036
3109
|
|
|
3037
3110
|
res_parts = ((mode == :singular) ? res_name.singularize : res_name).split('.')
|
|
@@ -198,7 +198,7 @@ function linkSchemas() {
|
|
|
198
198
|
|
|
199
199
|
# Treat ActiveStorage::Blob metadata as JSON
|
|
200
200
|
if ::Brick.config.table_name_prefixes.fetch('active_storage_', nil) == 'ActiveStorage' &&
|
|
201
|
-
ActiveStorage.const_defined?('Blob')
|
|
201
|
+
::ActiveStorage.const_defined?('Blob')
|
|
202
202
|
unless (md = (::Brick.config.model_descrips ||= {})).key?('ActiveStorage::Blob')
|
|
203
203
|
md['ActiveStorage::Blob'] = '[filename]'
|
|
204
204
|
end
|
|
@@ -641,6 +641,11 @@ window.addEventListener(\"popstate\", linkSchemas);
|
|
|
641
641
|
type_col = hm_assoc.inverse_of&.foreign_type || hm_assoc.type
|
|
642
642
|
keys << [type_col, poly_type]
|
|
643
643
|
end
|
|
644
|
+
# ActiveStorage has_one_attached and has_many_attached needs additional filtering on the name
|
|
645
|
+
if (as_name = hm_assoc.klass&._active_storage_name(hm_assoc.name)) # ActiveStorage HMT
|
|
646
|
+
prefix = 'attachments.' if hm_assoc.through_reflection&.klass&.<= ::ActiveStorage::Attachment
|
|
647
|
+
keys << ["#{prefix}name", as_name]
|
|
648
|
+
end
|
|
644
649
|
keys.to_h
|
|
645
650
|
end
|
|
646
651
|
|
|
@@ -1310,9 +1315,26 @@ end
|
|
|
1310
1315
|
# or
|
|
1311
1316
|
# Rails.application.reloader.to_prepare do ... end
|
|
1312
1317
|
self.class.class_exec { include ::Brick::Rails::FormTags } unless respond_to?(:brick_grid)
|
|
1313
|
-
|
|
1318
|
+
|
|
1319
|
+
#{# Determine if we should render an N:M representation or the standard "mega_grid"
|
|
1320
|
+
taa = ::Brick.config.treat_as_associative&.fetch(res_name, nil)
|
|
1321
|
+
options = {}
|
|
1322
|
+
options[:prefix] = prefix unless prefix.blank?
|
|
1323
|
+
if taa.is_a?(String) # Write out a constellation
|
|
1324
|
+
representation = :constellation
|
|
1325
|
+
"
|
|
1326
|
+
brick_constellation(@#{res_name}, #{options.inspect}, bt_descrip: @_brick_bt_descrip, bts: bts)"
|
|
1327
|
+
elsif taa.is_a?(Symbol) # Write out a bezier representation
|
|
1328
|
+
"
|
|
1329
|
+
brick_bezier(@#{res_name}, #{options.inspect}, bt_descrip: @_brick_bt_descrip, bts: bts)"
|
|
1330
|
+
else # Write out the mega-grid
|
|
1331
|
+
representation = :grid
|
|
1332
|
+
"
|
|
1314
1333
|
brick_grid(@#{res_name}, @_brick_sequence, @_brick_incl, @_brick_excl,
|
|
1315
|
-
cols, bt_descrip: @_brick_bt_descrip,
|
|
1334
|
+
cols, bt_descrip: @_brick_bt_descrip,
|
|
1335
|
+
poly_cols: poly_cols, bts: bts, hms_keys: #{hms_keys.inspect}, hms_cols: {#{hms_columns.join(', ')}})"
|
|
1336
|
+
end}
|
|
1337
|
+
%>
|
|
1316
1338
|
|
|
1317
1339
|
#{"<hr><%= link_to(\"New #{new_path_name = "new_#{path_obj_name}_path"
|
|
1318
1340
|
obj_name}\", #{new_path_name}, { class: '__brick' }) if respond_to?(:#{new_path_name}) %>" unless @_brick_model.is_view?}
|
|
@@ -1506,7 +1528,7 @@ end
|
|
|
1506
1528
|
|
|
1507
1529
|
if (pk = hm.first.klass.primary_key)
|
|
1508
1530
|
hm_singular_name = (hm_name = hm.first.name.to_s).singularize.underscore
|
|
1509
|
-
obj_br_pk =
|
|
1531
|
+
obj_br_pk = hm.first.klass._pk_as_array.map { |pk_part| "br_#{hm_singular_name}.#{pk_part}" }.join(', ')
|
|
1510
1532
|
poly_fix = if (poly_type = (hm.first.options[:as] && hm.first.type))
|
|
1511
1533
|
"
|
|
1512
1534
|
# Let's fix an unexpected \"feature\" of AR -- when going through a polymorphic has_many
|
|
@@ -1722,10 +1744,11 @@ flatpickr(\".timepicker\", {enableTime: true, noCalendar: true});
|
|
|
1722
1744
|
}
|
|
1723
1745
|
<%= \" showErd();\n\" if (@_brick_erd || 0) > 0
|
|
1724
1746
|
%></script>
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1747
|
+
<% end %>
|
|
1748
|
+
"
|
|
1749
|
+
end
|
|
1750
|
+
if representation == :grid
|
|
1751
|
+
"<script>
|
|
1729
1752
|
<% # Make column headers sort when clicked
|
|
1730
1753
|
# %%% Create a smart javascript routine which can do this client-side %>
|
|
1731
1754
|
[... document.getElementsByTagName(\"TH\")].forEach(function (th) {
|
|
@@ -84,7 +84,7 @@ module Brick::Rails::FormBuilder
|
|
|
84
84
|
opts = enum_type.send(:mapping)&.each_with_object([]) { |v, s| s << [v.first, v.first] } || []
|
|
85
85
|
out << self.select(method.to_sym, [["(No #{method} chosen)", '^^^brick_NULL^^^']] + opts, { value: val || '^^^brick_NULL^^^' }, options)
|
|
86
86
|
else
|
|
87
|
-
digit_pattern = col_type == :integer ? '\d*' : '\d*(?:\.\d*|)'
|
|
87
|
+
digit_pattern = col_type == :integer ? '(?:-|)\d*' : '(?:-|)\d*(?:\.\d*|)'
|
|
88
88
|
# Used to do this for float / decimal: self.number_field method.to_sym
|
|
89
89
|
out << self.text_field(method.to_sym, { pattern: digit_pattern, class: 'check-validity' })
|
|
90
90
|
end
|
|
@@ -110,6 +110,41 @@ module Brick::Rails::FormBuilder
|
|
|
110
110
|
::Brick::Rails.display_binary(val)
|
|
111
111
|
end
|
|
112
112
|
end
|
|
113
|
+
when :file, :files
|
|
114
|
+
if attached = begin
|
|
115
|
+
self.object.send(method)
|
|
116
|
+
rescue
|
|
117
|
+
end
|
|
118
|
+
# Show any existing image(s)
|
|
119
|
+
existing = []
|
|
120
|
+
got_one = nil
|
|
121
|
+
(attached.respond_to?(:attachments) ? attached.attachments : [attached]).each do |attachment|
|
|
122
|
+
next unless (blob = attachment.blob)
|
|
123
|
+
|
|
124
|
+
existing << blob.key
|
|
125
|
+
out << "#{blob.filename}<br>"
|
|
126
|
+
url = begin
|
|
127
|
+
self.object.send(method)&.url
|
|
128
|
+
rescue StandardError => e
|
|
129
|
+
# Another possible option:
|
|
130
|
+
# Rails.application.routes.url_helpers.rails_blob_path(attachment, only_path: true)
|
|
131
|
+
Rails.application.routes.url_helpers.rails_storage_proxy_path(attachment, only_path: true)
|
|
132
|
+
end
|
|
133
|
+
out << if url
|
|
134
|
+
"<img src=\"#{url}\" title=\"#{val}\">"
|
|
135
|
+
else # Convert the raw binary to a Base64 image
|
|
136
|
+
::Brick::Rails.display_binary(attachment.download, 500_000)
|
|
137
|
+
end
|
|
138
|
+
got_one = true
|
|
139
|
+
out << '<br>'
|
|
140
|
+
end
|
|
141
|
+
out << 'Update: ' if got_one
|
|
142
|
+
end
|
|
143
|
+
out << self.hidden_field("_brick_attached_#{method}", value: existing.join(',')) unless existing.blank?
|
|
144
|
+
# Render a "Choose File(s)" input element
|
|
145
|
+
args = [method.to_sym]
|
|
146
|
+
args << { multiple: true } if col&.type == :files
|
|
147
|
+
out << self.file_field(*args)
|
|
113
148
|
when :primary_key
|
|
114
149
|
is_revert = false
|
|
115
150
|
when :json, :jsonb
|
|
@@ -3,27 +3,9 @@ module Brick::Rails::FormTags
|
|
|
3
3
|
def brick_grid(relation = nil, sequence = nil, inclusions = nil, exclusions = nil,
|
|
4
4
|
cols = {}, bt_descrip: nil, poly_cols: nil, bts: {}, hms_keys: [], hms_cols: {},
|
|
5
5
|
show_header: nil, show_row_count: nil, show_erd_button: nil, show_in_app_button: nil, show_new_button: nil, show_avo_button: nil, show_aa_button: nil)
|
|
6
|
-
# When a relation is not provided, first see if one exists which matches the controller name
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
case (collections = _brick_resource_from_iv).length
|
|
10
|
-
when 0
|
|
11
|
-
puts '#brick_grid: Not having been provided with a collection to work from, searched through all instance variables to find an ActiveRecord::Relation. None could be found.'
|
|
12
|
-
return
|
|
13
|
-
when 1 # If there's only one type match then simply get the first one, hoping that this is what they intended
|
|
14
|
-
relation = instance_variable_get(iv = (chosen = collections.first).last.first)
|
|
15
|
-
puts "#brick_grid: Not having been provided with a collection to work from, first tried @#{controller_name}.
|
|
16
|
-
Failing that, have searched through instance variables and found #{iv} of type #{chosen.first.name}.
|
|
17
|
-
Running with it!"
|
|
18
|
-
else
|
|
19
|
-
myriad = collections.each_with_object([]) { |c, s| c.last.each { |iv| s << "#{iv} (#{c.first.name})" } }
|
|
20
|
-
puts "#brick_grid: Not having been provided with a collection to work from, first tried @#{controller_name}, and then searched through all instance variables.
|
|
21
|
-
Found ActiveRecord::Relation objects of multiple types:
|
|
22
|
-
#{myriad.inspect}
|
|
23
|
-
Not knowing which of these to render, have erred on the side of caution and simply provided this warning message."
|
|
24
|
-
return
|
|
25
|
-
end
|
|
26
|
-
end
|
|
6
|
+
# When a relation is not provided, first see if one exists which matches the controller name or
|
|
7
|
+
# something has turned up in the instance variables.
|
|
8
|
+
relation ||= (instance_variable_get("@#{controller_name}".to_sym) || _brick_resource_from_iv)
|
|
27
9
|
|
|
28
10
|
nfc = Brick.config.sidescroll.fetch(relation.table_name, nil)&.fetch(:num_frozen_columns, nil) ||
|
|
29
11
|
Brick.config.sidescroll.fetch(:num_frozen_columns, nil) ||
|
|
@@ -445,19 +427,25 @@ function onImagesLoaded(event) {
|
|
|
445
427
|
obj.send("#{model.brick_foreign_type(v.first)}=", v[1].first&.first&.name)
|
|
446
428
|
end
|
|
447
429
|
end if obj.new_record?
|
|
448
|
-
rtans = model.
|
|
449
|
-
(model.column_names +
|
|
430
|
+
hoa, hma, rtans = model._activestorage_actiontext_fields
|
|
431
|
+
(model.column_names + hoa + hma + rtans.keys).each do |k|
|
|
450
432
|
pk_pos = (pk.index(k)&.+ 1)
|
|
451
433
|
next if (pk_pos && pk.length == 1 && !bts.key?(k)) ||
|
|
452
434
|
::Brick.config.metadata_columns.include?(k)
|
|
453
435
|
|
|
454
436
|
col = model.columns_hash[k]
|
|
455
|
-
if !col
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
437
|
+
if !col
|
|
438
|
+
kwargs = if hoa.include?(k) # has_one_attached
|
|
439
|
+
{ sql_type: 'binary', type: :file }
|
|
440
|
+
elsif hma.include?(k) # has_many_attached
|
|
441
|
+
{ sql_type: 'binary', type: :files }
|
|
442
|
+
elsif rtans&.key?(k) # has_rich_text
|
|
443
|
+
k = rtans[k]
|
|
444
|
+
{ sql_type: 'varchar', type: :text }
|
|
445
|
+
end
|
|
446
|
+
col = (ActiveRecord::ConnectionAdapters::Column.new(
|
|
447
|
+
'', nil, ActiveRecord::ConnectionAdapters::SqlTypeMetadata.new(**kwargs)
|
|
448
|
+
)) if kwargs
|
|
461
449
|
end
|
|
462
450
|
val = obj.attributes[k]
|
|
463
451
|
out << "
|
|
@@ -535,6 +523,159 @@ function onImagesLoaded(event) {
|
|
|
535
523
|
end
|
|
536
524
|
end # brick_form_for
|
|
537
525
|
|
|
526
|
+
# ------------------------------------------
|
|
527
|
+
# Our cool N:M checkbox constellation editor
|
|
528
|
+
def brick_constellation(relation = nil, options = {}, x_axis: nil, y_axis: nil, bt_descrip: nil, bts: {})
|
|
529
|
+
x_axis, x_list, y_axis, y_list, existing = _n_m_prep(relation, x_axis, y_axis)
|
|
530
|
+
|
|
531
|
+
# HTML for constellation
|
|
532
|
+
prefix = options[:prefix]
|
|
533
|
+
out = +"<form action=\"#{"#{prefix}/" if prefix}brick_constellation\">
|
|
534
|
+
<table id=\"#{table_name = relation.table_name.split('.').last}\" class=\"shadow\">
|
|
535
|
+
<thead><tr><td></td>
|
|
536
|
+
"
|
|
537
|
+
# Header row with X axis values
|
|
538
|
+
x_list.each do |x_item|
|
|
539
|
+
out << " <th>#{x_item.first}</th>
|
|
540
|
+
"
|
|
541
|
+
end
|
|
542
|
+
out << " </tr></thead>
|
|
543
|
+
<tbody>
|
|
544
|
+
"
|
|
545
|
+
obj_path = "#{relation.klass._brick_index(:singular)}_path".to_sym
|
|
546
|
+
link_arrow = link_to('⇛', send(obj_path, '____'), { class: 'big-arrow' })
|
|
547
|
+
pk_as_array = relation.klass._pk_as_array
|
|
548
|
+
y_list.each do |y_item|
|
|
549
|
+
out << " <tr><th>#{y_item.first}</th>
|
|
550
|
+
"
|
|
551
|
+
x_list.each do |x_item|
|
|
552
|
+
checked = existing.find { |e| e[1] == x_item.last && e[2] == y_item.last }
|
|
553
|
+
item_id = pk_as_array.map { |pk_part| checked.first }.join('%2F') if checked
|
|
554
|
+
out << " <td><input type=\"checkbox\" name=\"#{table_name}\" #{"x-id=\"#{item_id}\" " if checked
|
|
555
|
+
}\" value=\"#{x_item.last}_#{y_item.last}\"#{' checked' if checked}>
|
|
556
|
+
#{link_arrow.gsub('____', item_id) if checked}</td>
|
|
557
|
+
"
|
|
558
|
+
end
|
|
559
|
+
out << " </tr>
|
|
560
|
+
"
|
|
561
|
+
end
|
|
562
|
+
out << " </tbody>
|
|
563
|
+
</table>
|
|
564
|
+
<script>
|
|
565
|
+
var constellation = document.getElementById(\"#{table_name}\");
|
|
566
|
+
var nextSib,
|
|
567
|
+
_this;
|
|
568
|
+
[... constellation.getElementsByTagName(\"INPUT\")].forEach(function (x) {
|
|
569
|
+
x.addEventListener(\"change\", function (y) {
|
|
570
|
+
_this = this;
|
|
571
|
+
if (this.checked) {
|
|
572
|
+
var ids = this.value.split(\"_\");
|
|
573
|
+
doFetch(\"POST\", {modelName: \"#{relation.klass.name}\",
|
|
574
|
+
args: [#{x_axis[1].inspect}, ids[0], #{y_axis[1].inspect}, ids[1]],
|
|
575
|
+
_brick_action: \"/#{prefix}brick_associate\"},
|
|
576
|
+
function (p) { // If it returns successfully, create an <a> element
|
|
577
|
+
p.text().then(function (response) {
|
|
578
|
+
var recordId = JSON.parse(response).data;
|
|
579
|
+
if (recordId) {
|
|
580
|
+
console.log(_this.getAttribute(\"x-id\"));
|
|
581
|
+
var tmp = document.createElement(\"DIV\");
|
|
582
|
+
tmp.innerHTML = \"#{link_arrow.gsub('"', '\"')}\".replace(\"____\", recordId);
|
|
583
|
+
_this.parentElement.append(tmp.firstChild);
|
|
584
|
+
}
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
);
|
|
588
|
+
} else if (nextSib = this.nextElementSibling) {
|
|
589
|
+
doFetch(\"DELETE\", {modelName: \"#{relation.klass.name}\",
|
|
590
|
+
id: this.getAttribute(\"x-id\"),
|
|
591
|
+
_brick_action: \"/#{prefix}brick_associate\"},
|
|
592
|
+
function (p) { // If it returns successfully, remove the an <a> element
|
|
593
|
+
_this.parentElement.removeChild(nextSib);
|
|
594
|
+
}
|
|
595
|
+
);
|
|
596
|
+
}
|
|
597
|
+
});
|
|
598
|
+
});
|
|
599
|
+
</script>
|
|
600
|
+
</form>
|
|
601
|
+
"
|
|
602
|
+
out.html_safe
|
|
603
|
+
end # brick_constellation
|
|
604
|
+
|
|
605
|
+
# ---------------------------------
|
|
606
|
+
# Our cool N:M bezier visualisation
|
|
607
|
+
# (...... work in progress .......)
|
|
608
|
+
def brick_bezier(relation = nil, options = {}, x_axis: nil, y_axis: nil, bt_descrip: nil, bts: {})
|
|
609
|
+
x_axis, x_list, y_axis, y_list, existing = _n_m_prep(relation, x_axis, y_axis)
|
|
610
|
+
# HTML for constellation
|
|
611
|
+
# X axis (List on left side)
|
|
612
|
+
out = +"<table id=\"#{x_axis.first}\" class=\"shadow\">
|
|
613
|
+
<tbody>
|
|
614
|
+
"
|
|
615
|
+
x_list.each_with_index { |x_item, idx| out << " <tr>#{"<th rowspan=\"#{x_list.length}\">#{x_axis.first}</th>" if idx.zero?}<td>#{x_item.first}</td></tr>" }
|
|
616
|
+
out << " </tbody>
|
|
617
|
+
</table>
|
|
618
|
+
"
|
|
619
|
+
|
|
620
|
+
# Y axis (List on right side)
|
|
621
|
+
out << "<table id=\"#{y_axis.first}\" class=\"shadow\">
|
|
622
|
+
<tbody>
|
|
623
|
+
"
|
|
624
|
+
y_list.each_with_index { |y_item, idx| out << " <tr><td>#{y_item.first}</td>#{"<th rowspan=\"#{y_list.length}\">#{y_axis.first}</th>" if idx.zero?}</tr>" }
|
|
625
|
+
out << " </tbody>
|
|
626
|
+
</table>
|
|
627
|
+
"
|
|
628
|
+
|
|
629
|
+
out.html_safe
|
|
630
|
+
end # brick_bezier
|
|
631
|
+
|
|
632
|
+
def _n_m_prep(relation, x_axis, y_axis)
|
|
633
|
+
relation ||= (instance_variable_get("@#{controller_name}".to_sym) || _brick_resource_from_iv)
|
|
634
|
+
# Just find the first two BT things at this point
|
|
635
|
+
|
|
636
|
+
klass = relation.klass
|
|
637
|
+
rel = ::Brick.relations&.fetch(relation.table_name, nil)
|
|
638
|
+
# fk_assocs = rel[:fks].map { |k, fk| [fk[:assoc_name], fk[:fk]] }
|
|
639
|
+
fk_assocs = klass.reflect_on_all_associations.each_with_object([]) do |assoc, s|
|
|
640
|
+
s << [assoc.name.to_s, assoc.foreign_key, assoc.klass] if assoc.belongs_to?
|
|
641
|
+
end
|
|
642
|
+
|
|
643
|
+
if (x_axis = fk_assocs.find { |assoc| assoc.include?(x_axis) })
|
|
644
|
+
fk_assocs -= x_axis
|
|
645
|
+
end
|
|
646
|
+
if (y_axis = fk_assocs.find { |assoc| assoc.include?(y_axis) })
|
|
647
|
+
fk_assocs -= y_axis
|
|
648
|
+
end
|
|
649
|
+
y_axis = fk_assocs.shift unless y_axis
|
|
650
|
+
x_axis = fk_assocs.shift unless x_axis
|
|
651
|
+
puts "FK Leftovers: #{fk_assocs.join(', ')}" unless fk_assocs.empty?
|
|
652
|
+
|
|
653
|
+
existing = relation.each_with_object([]) do |row, s|
|
|
654
|
+
row_id = row.send(klass.primary_key)
|
|
655
|
+
if (x_id = row.send(x_axis[1])) && (y_id = row.send(y_axis[1]))
|
|
656
|
+
s << [row_id, x_id, y_id]
|
|
657
|
+
end
|
|
658
|
+
end
|
|
659
|
+
x_list = _expand_collection(x_axis.last.all)
|
|
660
|
+
y_list = _expand_collection(y_axis.last.all)
|
|
661
|
+
[x_axis, x_list, y_axis, y_list, existing]
|
|
662
|
+
end
|
|
663
|
+
|
|
664
|
+
def _expand_collection(relation)
|
|
665
|
+
collection, descrip_cols = relation.brick_list
|
|
666
|
+
details = []
|
|
667
|
+
obj_pk = relation.klass.primary_key
|
|
668
|
+
collection&.brick_(:each) do |obj|
|
|
669
|
+
details << [
|
|
670
|
+
obj.brick_descrip(
|
|
671
|
+
descrip_cols&.first&.map { |col2| obj.send(col2.last) },
|
|
672
|
+
obj_pk
|
|
673
|
+
), obj.send(obj_pk)
|
|
674
|
+
]
|
|
675
|
+
end
|
|
676
|
+
details
|
|
677
|
+
end
|
|
678
|
+
|
|
538
679
|
# --------------------------------
|
|
539
680
|
def link_to_brick(*args, **kwargs)
|
|
540
681
|
return unless ::Brick.config.mode == :on
|
|
@@ -621,7 +762,7 @@ function onImagesLoaded(event) {
|
|
|
621
762
|
else
|
|
622
763
|
# puts "Warning: link_to_brick could not find a class for \"#{controller_path}\" -- consider setting @_brick_model within that controller."
|
|
623
764
|
# if (hits = res_names.keys & instance_variables.map { |v| v.to_s[1..-1] }).present?
|
|
624
|
-
if (links =
|
|
765
|
+
if (links = _brick_relation_from_iv(true)).length == 1 # If there's only one match then use any text that was supplied
|
|
625
766
|
link_to_brick(text || links.first.last.join('/'), links.first.first, **kwargs)
|
|
626
767
|
else
|
|
627
768
|
links.each_with_object([]) do |v, s|
|
|
@@ -671,7 +812,7 @@ btnAddCol.addEventListener(\"click\", function () {
|
|
|
671
812
|
private
|
|
672
813
|
|
|
673
814
|
# Dig through all instance variables with hopes to find any that appear related to ActiveRecord
|
|
674
|
-
def
|
|
815
|
+
def _brick_relation_from_iv(trim_ampersand = false)
|
|
675
816
|
instance_variables.each_with_object(Hash.new { |h, k| h[k] = [] }) do |name, s|
|
|
676
817
|
iv_name = trim_ampersand ? name.to_s[1..-1] : name
|
|
677
818
|
case (val = instance_variable_get(name))
|
|
@@ -682,4 +823,26 @@ private
|
|
|
682
823
|
end
|
|
683
824
|
end
|
|
684
825
|
end
|
|
826
|
+
|
|
827
|
+
def _brick_resource_from_iv
|
|
828
|
+
# Failing that, dig through the instance variables with hopes to find something that is an ActiveRecord::Relation
|
|
829
|
+
case (collections = _brick_relation_from_iv).length
|
|
830
|
+
when 0
|
|
831
|
+
puts '#brick_grid: Not having been provided with a collection to work from, searched through all instance variables to find an ActiveRecord::Relation. None could be found.'
|
|
832
|
+
return
|
|
833
|
+
when 1 # If there's only one type match then simply get the first one, hoping that this is what they intended
|
|
834
|
+
relation = instance_variable_get(iv = (chosen = collections.first).last.first)
|
|
835
|
+
puts "#brick_grid: Not having been provided with a collection to work from, first tried @#{controller_name}.
|
|
836
|
+
Failing that, have searched through instance variables and found #{iv} of type #{chosen.first.name}.
|
|
837
|
+
Running with it!"
|
|
838
|
+
relation
|
|
839
|
+
else
|
|
840
|
+
myriad = collections.each_with_object([]) { |c, s| c.last.each { |iv| s << "#{iv} (#{c.first.name})" } }
|
|
841
|
+
puts "#brick_grid: Not having been provided with a collection to work from, first tried @#{controller_name}, and then searched through all instance variables.
|
|
842
|
+
Found ActiveRecord::Relation objects of multiple types:
|
|
843
|
+
#{myriad.inspect}
|
|
844
|
+
Not knowing which of these to render, have erred on the side of caution and simply provided this warning message."
|
|
845
|
+
return
|
|
846
|
+
end
|
|
847
|
+
end
|
|
685
848
|
end
|
|
@@ -173,7 +173,12 @@ erDiagram
|
|
|
173
173
|
<%= erd_sidelinks(shown_classes, hm_class).html_safe %>
|
|
174
174
|
<% end
|
|
175
175
|
def dt_lookup(dt)
|
|
176
|
-
|
|
176
|
+
puts dt.inspect
|
|
177
|
+
{ 'integer' => 'int', 'character varying' => 'varchar', 'double precision' => 'float',
|
|
178
|
+
'timestamp without time zone' => 'timestamp',
|
|
179
|
+
'timestamp with time zone' => 'timestamp',
|
|
180
|
+
'time without time zone' => 'time',
|
|
181
|
+
'time with time zone' => 'time' }[dt] || dt&.tr(' ', '_') || 'int'
|
|
177
182
|
end
|
|
178
183
|
callbacks.merge({#{model_short_name.inspect} => #{model.name}}).each do |cb_k, cb_class|
|
|
179
184
|
cb_relation = ::Brick.relations[cb_class.table_name]
|
|
@@ -193,6 +198,12 @@ erDiagram
|
|
|
193
198
|
%>
|
|
194
199
|
<%= \"#\{dt_lookup(cols[fk]&.first)} #\{fk} \\\" fk\\\"\".html_safe unless pkeys&.include?(fk) %><%
|
|
195
200
|
end
|
|
201
|
+
end %><%
|
|
202
|
+
if (erd_sc = Brick.config.erd_show_columns) == true || erd_sc&.include?(cb_class.name)
|
|
203
|
+
cols&.each do |col|
|
|
204
|
+
next if pkeys.include?(col.first) || fkeys.include?(col.first) %>
|
|
205
|
+
<%= \"#\{dt_lookup(col[1]&.first&.to_s)} #\{col.first}\".html_safe %><%
|
|
206
|
+
end
|
|
196
207
|
end %>
|
|
197
208
|
}
|
|
198
209
|
<% end
|
data/lib/brick/route_mapper.rb
CHANGED
|
@@ -287,6 +287,15 @@ module Brick
|
|
|
287
287
|
# post("/#{controller_prefix}brick_schema", to: 'brick_gem#schema_create', as: schema_as.to_s)
|
|
288
288
|
# end
|
|
289
289
|
|
|
290
|
+
if (associate_as = "#{controller_prefix.tr('/', '_')}brick_associate".to_sym)
|
|
291
|
+
(
|
|
292
|
+
!(associate_route = instance_variable_get(:@set).named_routes.find { |route| route.first == associate_as }&.last) ||
|
|
293
|
+
!associate_route.ast.to_s.include?("/#{controller_prefix}brick_associate/")
|
|
294
|
+
)
|
|
295
|
+
post("/#{controller_prefix}brick_associate", to: 'brick_gem#associate', as: associate_as.to_s)
|
|
296
|
+
delete("/#{controller_prefix}brick_associate", to: 'brick_gem#unassociate')
|
|
297
|
+
end
|
|
298
|
+
|
|
290
299
|
if ::Brick.config.add_orphans && (orphans_as = "#{controller_prefix.tr('/', '_')}brick_orphans".to_sym)
|
|
291
300
|
(
|
|
292
301
|
!(orphans_route = instance_variable_get(:@set).named_routes.find { |route| route.first == orphans_as }&.last) ||
|
data/lib/brick/version_number.rb
CHANGED
|
@@ -310,6 +310,14 @@ if ActiveRecord::Base.respond_to?(:brick_select) && !::Brick.initializer_loaded
|
|
|
310
310
|
# # have a table to still be treated as associative, causing HMTs to be auto-generated.)
|
|
311
311
|
# Brick.treat_as_associative = ['flights']
|
|
312
312
|
|
|
313
|
+
# # Further, if you want to present a given associative table in various ways then you can choose a 2D
|
|
314
|
+
# # constellation map of checkboxes, or bezier curves showing the association between a list at the left and at
|
|
315
|
+
# # the right. Indicating just :bezier is the same as :bezier_full, which shows the full list of all possible
|
|
316
|
+
# # things that can be associated. :bezier_union shows just the ones that are currently wired up, and
|
|
317
|
+
# # :bezier_excluded, :bezier_excluded_left, or :bezier_excluded_right shows the ones not yet wired up.
|
|
318
|
+
# Brick.treat_as_associative = { 'flights' => [:bezier, 'departure.code', 'arrival.code'],
|
|
319
|
+
# 'crew' => [:constellation, 'flight', 'personnel', '[used ? [used it!] : []]'] }
|
|
320
|
+
|
|
313
321
|
# # We normally don't show the timestamp columns \"created_at\", \"updated_at\", and \"deleted_at\", and also do
|
|
314
322
|
# # not consider them when finding associative tables to support an N:M association. (That is, ones that can be a
|
|
315
323
|
# # part of a has_many :through association.) If you want to use different exclusion columns than our defaults
|
|
@@ -334,6 +342,14 @@ if ActiveRecord::Base.respond_to?(:brick_select) && !::Brick.initializer_loaded
|
|
|
334
342
|
# # user, then you can use model_descrips like this, putting expressions with property references in square brackets:
|
|
335
343
|
# Brick.model_descrips = { 'User' => '[profile.firstname] [profile.lastname]' }
|
|
336
344
|
|
|
345
|
+
# # ERD SETTINGS
|
|
346
|
+
|
|
347
|
+
# # By default the Entity Relationship Diagram fragment which is available to be shown on the Grid page includes
|
|
348
|
+
# # primary and foreign keys. In order for it to show all columns in all cases, set this value to +true+:
|
|
349
|
+
# Brick.config.erd_show_columns = true
|
|
350
|
+
# # or to show all columns for specific tables, supply an array of model names:
|
|
351
|
+
# Brick.config.erd_show_columns = ['User', 'OrderDetail']
|
|
352
|
+
|
|
337
353
|
# # SINGLE TABLE INHERITANCE
|
|
338
354
|
|
|
339
355
|
# # Specify STI subclasses either directly by name or as a general module prefix that should always relate to a specific
|
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.212
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Lorin Thwaits
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2024-03-
|
|
11
|
+
date: 2024-03-28 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activerecord
|
|
@@ -285,7 +285,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
285
285
|
- !ruby/object:Gem::Version
|
|
286
286
|
version: 1.3.6
|
|
287
287
|
requirements: []
|
|
288
|
-
rubygems_version: 3.
|
|
288
|
+
rubygems_version: 3.2.33
|
|
289
289
|
signing_key:
|
|
290
290
|
specification_version: 4
|
|
291
291
|
summary: Create a Rails app from data alone
|