brick 1.0.72 → 1.0.73
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/brick/config.rb +25 -0
- data/lib/brick/extensions.rb +180 -95
- data/lib/brick/frameworks/rails/engine.rb +56 -25
- data/lib/brick/version_number.rb +1 -1
- data/lib/brick.rb +38 -10
- data/lib/generators/brick/install_generator.rb +2 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 31f69b5035fcebf947e729c3ebabdf3a686c364fb9ddc6a764a2b34740fdb7c9
|
4
|
+
data.tar.gz: 87009aad044a5a110146d26dc02f62451b18e7ad67b2b07d420edff0718a18c6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 300fe830280b2ad9d265fa62166aac01ba3e511090f95efa412d1b9ed42fbd72b9f17f8fe51ac1bb358be42f012b46cffbb3c142f6fd3b11f2a442025824e8ec
|
7
|
+
data.tar.gz: abbd021f67adb2c03aae76340ba1cb1f38d0be5b5774d11c5a01a1315e02b80c293c9008021915315416da28937b40af59d821e41ad6ac0eed890be162865d98
|
data/lib/brick/config.rb
CHANGED
@@ -56,6 +56,31 @@ module Brick
|
|
56
56
|
@mutex.synchronize { @enable_routes = enable }
|
57
57
|
end
|
58
58
|
|
59
|
+
def enable_api
|
60
|
+
@mutex.synchronize { @enable_api }
|
61
|
+
end
|
62
|
+
|
63
|
+
def enable_api=(enable)
|
64
|
+
@mutex.synchronize { @enable_api = enable }
|
65
|
+
end
|
66
|
+
|
67
|
+
def api_root
|
68
|
+
ver = api_version
|
69
|
+
@mutex.synchronize { @api_root || "/api/#{ver}/" }
|
70
|
+
end
|
71
|
+
|
72
|
+
def api_root=(path)
|
73
|
+
@mutex.synchronize { @api_root = path }
|
74
|
+
end
|
75
|
+
|
76
|
+
def api_version
|
77
|
+
@mutex.synchronize { @api_version || 'v1' }
|
78
|
+
end
|
79
|
+
|
80
|
+
def api_version=(ver)
|
81
|
+
@mutex.synchronize { @api_version = ver }
|
82
|
+
end
|
83
|
+
|
59
84
|
# Additional table associations to use (Think of these as virtual foreign keys perhaps)
|
60
85
|
def additional_references
|
61
86
|
@mutex.synchronize { @additional_references }
|
data/lib/brick/extensions.rb
CHANGED
@@ -107,7 +107,8 @@ module ActiveRecord
|
|
107
107
|
bracket_name = nil
|
108
108
|
prefix = [prefix] unless prefix.is_a?(Array)
|
109
109
|
if (dsl = ::Brick.config.model_descrips[name] || brick_get_dsl)
|
110
|
-
dsl2 = +''
|
110
|
+
dsl2 = +'' # To replace our own DSL definition in case it needs to be expanded
|
111
|
+
dsl3 = +'' # To return expanded DSL that is nested from another model
|
111
112
|
klass = nil
|
112
113
|
dsl.each_char do |ch|
|
113
114
|
if bracket_name
|
@@ -129,11 +130,16 @@ module ActiveRecord
|
|
129
130
|
end
|
130
131
|
if klass.column_names.exclude?(parts.last) &&
|
131
132
|
(klass = (orig_class = klass).reflect_on_association(possible_dsl = parts.pop.to_sym)&.klass)
|
133
|
+
# Expand this entry which refers to an association name
|
132
134
|
members2, dsl2a = klass.brick_parse_dsl(build_array, prefix + [possible_dsl], translations, true)
|
133
135
|
members += members2
|
134
136
|
dsl2 << dsl2a
|
137
|
+
dsl3 << dsl2a
|
135
138
|
else
|
136
139
|
dsl2 << "[#{bracket_name}]"
|
140
|
+
if emit_dsl
|
141
|
+
dsl3 << "[#{prefix[1..-1].map { |p| "#{p.to_s}." }.join if prefix.length > 1}#{bracket_name}]"
|
142
|
+
end
|
137
143
|
members << parts
|
138
144
|
end
|
139
145
|
bracket_name = nil
|
@@ -145,15 +151,22 @@ module ActiveRecord
|
|
145
151
|
klass = self
|
146
152
|
else
|
147
153
|
dsl2 << ch
|
154
|
+
dsl3 << ch
|
148
155
|
end
|
149
156
|
end
|
150
157
|
# Rewrite the DSL in case it's now different from having to expand it
|
158
|
+
# if ::Brick.config.model_descrips[name] != dsl2
|
159
|
+
# puts ::Brick.config.model_descrips[name]
|
160
|
+
# puts dsl2.inspect
|
161
|
+
# puts dsl3.inspect
|
162
|
+
# binding.pry
|
163
|
+
# end
|
151
164
|
::Brick.config.model_descrips[name] = dsl2 unless emit_dsl
|
152
165
|
else # With no DSL available, still put this prefix into the JoinArray so we can get primary key (ID) info from this table
|
153
166
|
x = prefix.each_with_object(build_array) { |v, s| s[v.to_sym] }
|
154
167
|
x[prefix.last] = nil unless prefix.empty? # Using []= will "hydrate" any missing part(s) in our whole series
|
155
168
|
end
|
156
|
-
emit_dsl ? [members,
|
169
|
+
emit_dsl ? [members, dsl3] : members
|
157
170
|
end
|
158
171
|
|
159
172
|
# If available, parse simple DSL attached to a model in order to provide a friendlier name.
|
@@ -221,13 +234,21 @@ module ActiveRecord
|
|
221
234
|
end
|
222
235
|
|
223
236
|
def self.bt_link(assoc_name)
|
224
|
-
model_underscore = name.underscore
|
225
237
|
assoc_name = CGI.escapeHTML(assoc_name.to_s)
|
226
|
-
model_path = Rails.application.routes.url_helpers.send("#{
|
238
|
+
model_path = Rails.application.routes.url_helpers.send("#{_brick_index}_path".to_sym)
|
227
239
|
av_class = Class.new.extend(ActionView::Helpers::UrlHelper)
|
228
240
|
av_class.extend(ActionView::Helpers::TagHelper) if ActionView.version < ::Gem::Version.new('7')
|
229
241
|
link = av_class.link_to(name, model_path)
|
230
|
-
|
242
|
+
table_name == assoc_name ? link : "#{assoc_name}-#{link}".html_safe
|
243
|
+
end
|
244
|
+
|
245
|
+
def self._brick_index
|
246
|
+
tbl_parts = table_name.split('.')
|
247
|
+
tbl_parts.shift if ::Brick.apartment_multitenant && tbl_parts.first == Apartment.default_schema
|
248
|
+
if (index = tbl_parts.map(&:underscore).join('_')) == index.singularize
|
249
|
+
index << '_index' # Rails applies an _index suffix to that route when the resource name is singular
|
250
|
+
end
|
251
|
+
index
|
231
252
|
end
|
232
253
|
|
233
254
|
def self.brick_import_template
|
@@ -407,7 +428,7 @@ module ActiveRecord
|
|
407
428
|
is_distinct = nil
|
408
429
|
wheres = {}
|
409
430
|
params.each do |k, v|
|
410
|
-
next if ['_brick_schema', '_brick_order'].include?(k)
|
431
|
+
next if ['_brick_schema', '_brick_order', 'controller', 'action'].include?(k)
|
411
432
|
|
412
433
|
case (ks = k.split('.')).length
|
413
434
|
when 1
|
@@ -427,6 +448,9 @@ module ActiveRecord
|
|
427
448
|
# %%% Skip the metadata columns
|
428
449
|
if selects&.empty? # Default to all columns
|
429
450
|
tbl_no_schema = table.name.split('.').last
|
451
|
+
# %%% Have once gotten this error with MSSQL referring to http://localhost:3000/warehouse/cold_room_temperatures__archive
|
452
|
+
# ActiveRecord::StatementInvalid (TinyTds::Error: DBPROCESS is dead or not enabled)
|
453
|
+
# Relevant info here: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/issues/402
|
430
454
|
columns.each do |col|
|
431
455
|
col_alias = " AS #{col.name}_" if (col_name = col.name) == 'class'
|
432
456
|
selects << if is_mysql
|
@@ -726,7 +750,8 @@ Module.class_exec do
|
|
726
750
|
# Vabc instead of VABC)
|
727
751
|
full_class_name = +''
|
728
752
|
full_class_name << "::#{self.name}" unless self == Object
|
729
|
-
|
753
|
+
singular_class_name = ::Brick.namify(plural_class_name, :underscore).singularize.camelize
|
754
|
+
full_class_name << "::#{singular_class_name}"
|
730
755
|
if plural_class_name == 'BrickSwagger' ||
|
731
756
|
(
|
732
757
|
(::Brick.config.add_status || ::Brick.config.add_orphans) &&
|
@@ -1111,64 +1136,63 @@ class Object
|
|
1111
1136
|
end
|
1112
1137
|
return [new_controller_class, code + "end # BrickGem controller\n"]
|
1113
1138
|
when 'BrickSwagger'
|
1114
|
-
is_swagger = true
|
1139
|
+
is_swagger = true
|
1115
1140
|
end
|
1116
1141
|
|
1117
1142
|
self.protect_from_forgery unless: -> { self.request.format.js? }
|
1118
1143
|
self.define_method :index do
|
1119
|
-
# We do all of this now so that bt_descrip and hm_counts are available on the model early in case the user
|
1120
|
-
# wants to do an ORDER BY based on any of that
|
1121
|
-
translations = {}
|
1122
|
-
join_array = ::Brick::JoinArray.new
|
1123
|
-
is_add_bts = is_add_hms = true
|
1124
|
-
# This builds out bt_descrip and hm_counts on the model
|
1125
|
-
model._brick_calculate_bts_hms(translations, join_array) if is_add_bts || is_add_hms
|
1126
|
-
|
1127
1144
|
if is_swagger
|
1128
|
-
|
1145
|
+
if !params&.key?('_brick_schema') &&
|
1146
|
+
(referrer_params = request.env['HTTP_REFERER']&.split('?')&.last&.split('&')&.map { |x| x.split('=') }).present?
|
1147
|
+
if params
|
1148
|
+
referrer_params.each { |k, v| params.send(:parameters)[k] = v }
|
1149
|
+
else
|
1150
|
+
api_params = referrer_params&.to_h
|
1151
|
+
end
|
1152
|
+
end
|
1153
|
+
::Brick.set_db_schema(params || api_params)
|
1154
|
+
json = { 'openapi': '3.0.1', 'info': { 'title': Rswag::Ui.config.config_object[:urls].last&.fetch(:name, 'API documentation'), 'version': ::Brick.config.api_version },
|
1129
1155
|
'servers': [
|
1130
|
-
{ 'url': '
|
1156
|
+
{ 'url': '{scheme}://{defaultHost}', 'variables': {
|
1157
|
+
'scheme': { 'default': request.env['rack.url_scheme'] },
|
1158
|
+
'defaultHost': { 'default': request.env['HTTP_HOST'] }
|
1159
|
+
} }
|
1131
1160
|
]
|
1132
1161
|
}
|
1133
|
-
json['paths'] = relations.inject({}) do |s,
|
1134
|
-
|
1135
|
-
|
1136
|
-
|
1137
|
-
'
|
1138
|
-
|
1139
|
-
|
1140
|
-
|
1141
|
-
|
1142
|
-
|
1143
|
-
|
1144
|
-
|
1145
|
-
|
1146
|
-
|
1147
|
-
|
1148
|
-
|
1149
|
-
'responses': { '200': { 'description': 'successful' } }
|
1162
|
+
json['paths'] = relations.inject({}) do |s, relation|
|
1163
|
+
unless ::Brick.config.enable_api == false
|
1164
|
+
table_description = relation.last[:description]
|
1165
|
+
s["#{::Brick.config.api_root}#{relation.first.tr('.', '/')}"] = {
|
1166
|
+
'get': {
|
1167
|
+
'summary': "list #{relation.first}",
|
1168
|
+
'description': table_description,
|
1169
|
+
'parameters': relation.last[:cols].map do |k, v|
|
1170
|
+
param = { 'name' => k, 'schema': { 'type': v.first } }
|
1171
|
+
if (col_descrip = relation.last.fetch(:col_descrips, nil)&.fetch(k, nil))
|
1172
|
+
param['description'] = col_descrip
|
1173
|
+
end
|
1174
|
+
param
|
1175
|
+
end,
|
1176
|
+
'responses': { '200': { 'description': 'successful' } }
|
1177
|
+
}
|
1150
1178
|
}
|
1151
|
-
|
1152
|
-
#
|
1153
|
-
|
1154
|
-
|
1155
|
-
|
1156
|
-
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
1160
|
-
|
1161
|
-
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1168
|
-
# }
|
1169
|
-
# ],
|
1170
|
-
}
|
1171
|
-
s
|
1179
|
+
|
1180
|
+
s["#{::Brick.config.api_root}#{relation.first.tr('.', '/')}/{id}"] = {
|
1181
|
+
'patch': {
|
1182
|
+
'summary': "update a #{relation.first.singularize}",
|
1183
|
+
'description': table_description,
|
1184
|
+
'parameters': relation.last[:cols].reject { |k, v| Brick.config.metadata_columns.include?(k) }.map do |k, v|
|
1185
|
+
param = { 'name' => k, 'schema': { 'type': v.first } }
|
1186
|
+
if (col_descrip = relation.last.fetch(:col_descrips, nil)&.fetch(k, nil))
|
1187
|
+
param['description'] = col_descrip
|
1188
|
+
end
|
1189
|
+
param
|
1190
|
+
end,
|
1191
|
+
'responses': { '200': { 'description': 'successful' } }
|
1192
|
+
}
|
1193
|
+
} unless relation.last.fetch(:isView, nil)
|
1194
|
+
s
|
1195
|
+
end
|
1172
1196
|
end
|
1173
1197
|
render inline: json.to_json, content_type: request.format
|
1174
1198
|
return
|
@@ -1176,6 +1200,14 @@ class Object
|
|
1176
1200
|
|
1177
1201
|
# Normal (non-swagger) request
|
1178
1202
|
|
1203
|
+
# We do all of this now so that bt_descrip and hm_counts are available on the model early in case the user
|
1204
|
+
# wants to do an ORDER BY based on any of that
|
1205
|
+
translations = {}
|
1206
|
+
join_array = ::Brick::JoinArray.new
|
1207
|
+
is_add_bts = is_add_hms = true
|
1208
|
+
# This builds out bt_descrip and hm_counts on the model
|
1209
|
+
model._brick_calculate_bts_hms(translations, join_array) if is_add_bts || is_add_hms
|
1210
|
+
|
1179
1211
|
# %%% Allow params to define which columns to use for order_by
|
1180
1212
|
# Overriding the default by providing a querystring param?
|
1181
1213
|
ordering = params['_brick_order']&.split(',')&.map(&:to_sym) || Object.send(:default_ordering, table_name, pk)
|
@@ -1189,8 +1221,9 @@ class Object
|
|
1189
1221
|
end
|
1190
1222
|
render inline: exported_csv, content_type: request.format
|
1191
1223
|
return
|
1192
|
-
elsif request.format == :js # Asking for JSON?
|
1193
|
-
|
1224
|
+
elsif request.format == :js || request.path.start_with?('/api/') # Asking for JSON?
|
1225
|
+
data = (model.is_view? || !Object.const_defined?('DutyFree')) ? model.limit(1000) : model.df_export(model.brick_import_template)
|
1226
|
+
render inline: data.to_json, content_type: request.format == '*/*' ? 'application/json' : request.format
|
1194
1227
|
return
|
1195
1228
|
end
|
1196
1229
|
|
@@ -1206,7 +1239,7 @@ class Object
|
|
1206
1239
|
"b_r_#{v.first}.c_t_ AS \"b_r_#{v.first}_ct\""
|
1207
1240
|
end
|
1208
1241
|
end
|
1209
|
-
instance_variable_set("@#{table_name}".to_sym, ar_relation.dup._select!(*selects, *counts))
|
1242
|
+
instance_variable_set("@#{table_name.pluralize}".to_sym, ar_relation.dup._select!(*selects, *counts))
|
1210
1243
|
if namespace && (idx = lookup_context.prefixes.index(table_name))
|
1211
1244
|
lookup_context.prefixes[idx] = "#{namespace.name.underscore}/#{lookup_context.prefixes[idx]}"
|
1212
1245
|
end
|
@@ -1221,32 +1254,34 @@ class Object
|
|
1221
1254
|
@_brick_erd = params['_brick_erd']&.to_i
|
1222
1255
|
end
|
1223
1256
|
|
1224
|
-
|
1225
|
-
|
1226
|
-
|
1227
|
-
|
1228
|
-
|
1229
|
-
|
1230
|
-
is_pk_string = nil
|
1231
|
-
if (pk_col = model&.primary_key)
|
1232
|
-
code << " def show\n"
|
1233
|
-
code << " #{find_by_name = "find_#{singular_table_name}"}\n"
|
1257
|
+
unless is_swagger
|
1258
|
+
::Brick.set_db_schema
|
1259
|
+
_, order_by_txt = model._brick_calculate_ordering(default_ordering(table_name, pk)) if pk
|
1260
|
+
code << " def index\n"
|
1261
|
+
code << " @#{table_name.pluralize} = #{model.name}#{pk&.present? ? ".order(#{order_by_txt.join(', ')})" : '.all'}\n"
|
1262
|
+
code << " @#{table_name.pluralize}.brick_select(params)\n"
|
1234
1263
|
code << " end\n"
|
1235
|
-
|
1236
|
-
|
1237
|
-
|
1238
|
-
|
1239
|
-
|
1240
|
-
|
1241
|
-
|
1242
|
-
|
1243
|
-
|
1244
|
-
|
1264
|
+
|
1265
|
+
is_pk_string = nil
|
1266
|
+
if pk.present?
|
1267
|
+
code << " def show\n"
|
1268
|
+
code << " #{find_by_name = "find_#{singular_table_name}"}\n"
|
1269
|
+
code << " end\n"
|
1270
|
+
self.define_method :show do
|
1271
|
+
::Brick.set_db_schema(params)
|
1272
|
+
id = if model.columns_hash[pk.first]&.type == :string
|
1273
|
+
is_pk_string = true
|
1274
|
+
params[:id]
|
1275
|
+
else
|
1276
|
+
params[:id]&.split(/[\/,_]/)
|
1277
|
+
end
|
1278
|
+
id = id.first if id.is_a?(Array) && id.length == 1
|
1279
|
+
instance_variable_set("@#{singular_table_name}".to_sym, find_obj)
|
1280
|
+
end
|
1245
1281
|
end
|
1246
|
-
end
|
1247
1282
|
|
1248
|
-
|
1249
|
-
|
1283
|
+
# By default, views get marked as read-only
|
1284
|
+
# unless model.readonly # (relation = relations[model.table_name]).key?(:isView)
|
1250
1285
|
code << " def new\n"
|
1251
1286
|
code << " @#{singular_table_name} = #{model.name}.new\n"
|
1252
1287
|
code << " end\n"
|
@@ -1280,7 +1315,7 @@ class Object
|
|
1280
1315
|
end
|
1281
1316
|
end
|
1282
1317
|
|
1283
|
-
if
|
1318
|
+
if pk.present?
|
1284
1319
|
# if (schema = ::Brick.config.schema_behavior[:multitenant]&.fetch(:schema_to_analyse, nil)) && ::Brick.db_schemas&.include?(schema)
|
1285
1320
|
# ActiveRecord::Base.execute_sql("SET SEARCH_PATH = ?;", schema)
|
1286
1321
|
# end
|
@@ -1327,9 +1362,9 @@ class Object
|
|
1327
1362
|
end
|
1328
1363
|
end
|
1329
1364
|
|
1330
|
-
code << "private\n" if
|
1365
|
+
code << "private\n" if pk.present? || is_need_params
|
1331
1366
|
|
1332
|
-
if
|
1367
|
+
if pk.present?
|
1333
1368
|
code << " def find_#{singular_table_name}
|
1334
1369
|
id = params[:id]&.split(/[\\/,_]/)
|
1335
1370
|
@#{singular_table_name} = #{model.name}.find(id.is_a?(Array) && id.length == 1 ? id.first : id)
|
@@ -1357,16 +1392,16 @@ class Object
|
|
1357
1392
|
private params_name
|
1358
1393
|
# Get column names for params from relations[model.table_name][:cols].keys
|
1359
1394
|
end
|
1360
|
-
#
|
1395
|
+
end # unless is_swagger
|
1361
1396
|
code << "end # #{namespace_name}#{class_name}\n"
|
1362
1397
|
end # class definition
|
1363
1398
|
[built_controller, code]
|
1364
1399
|
end
|
1365
1400
|
|
1366
1401
|
def _brick_get_hm_assoc_name(relation, hm_assoc, source = nil)
|
1367
|
-
if (relation[:hm_counts][hm_assoc[:
|
1402
|
+
if (relation[:hm_counts][hm_assoc[:inverse_table]]&.> 1) &&
|
1368
1403
|
hm_assoc[:alternate_name] != (source || name.underscore)
|
1369
|
-
plural = ActiveSupport::Inflector.pluralize(hm_assoc[:alternate_name])
|
1404
|
+
plural = "#{hm_assoc[:assoc_name]}_#{ActiveSupport::Inflector.pluralize(hm_assoc[:alternate_name])}"
|
1370
1405
|
new_alt_name = (hm_assoc[:alternate_name] == name.underscore) ? "#{hm_assoc[:assoc_name].singularize}_#{plural}" : plural
|
1371
1406
|
# uniq = 1
|
1372
1407
|
# while same_name = relation[:fks].find { |x| x.last[:assoc_name] == hm_assoc[:assoc_name] && x.last != hm_assoc }
|
@@ -1497,6 +1532,8 @@ module ActiveRecord::ConnectionHandling
|
|
1497
1532
|
r['schema']
|
1498
1533
|
end
|
1499
1534
|
relation_name = schema_name ? "#{schema_name}.#{r['relation_name']}" : r['relation_name']
|
1535
|
+
# Both uppers and lowers as well as underscores?
|
1536
|
+
apply_double_underscore_patch if relation_name =~ /[A-Z]/ && relation_name =~ /[a-z]/ && relation_name.index('_')
|
1500
1537
|
relation = relations[relation_name]
|
1501
1538
|
relation[:isView] = true if r['table_type'] == 'VIEW'
|
1502
1539
|
relation[:description] = r['table_description'] if r['table_description']
|
@@ -1513,6 +1550,7 @@ module ActiveRecord::ConnectionHandling
|
|
1513
1550
|
cols = relation[:cols] # relation.fetch(:cols) { relation[:cols] = [] }
|
1514
1551
|
cols[col_name] = [r['data_type'], r['max_length'], measures&.include?(col_name), r['is_nullable'] == 'NO']
|
1515
1552
|
# puts "KEY! #{r['relation_name']}.#{col_name} #{r['key']} #{r['const']}" if r['key']
|
1553
|
+
relation[:col_descrips][col_name] = r['column_description'] if r['column_description']
|
1516
1554
|
end
|
1517
1555
|
else # MySQL2 and OracleEnhanced act a little differently, bringing back an array for each row
|
1518
1556
|
schema_and_tables = case ActiveRecord::Base.connection.adapter_name
|
@@ -1542,6 +1580,9 @@ ORDER BY 1, 2, c.internal_column_id, acc.position"
|
|
1542
1580
|
|
1543
1581
|
if (relation_name = r[1]) =~ /^[A-Z0-9_]+$/
|
1544
1582
|
relation_name.downcase!
|
1583
|
+
# Both uppers and lowers as well as underscores?
|
1584
|
+
elsif relation_name =~ /[A-Z]/ && relation_name =~ /[a-z]/ && relation_name.index('_')
|
1585
|
+
apply_double_underscore_patch
|
1545
1586
|
end
|
1546
1587
|
# Expect the default schema for SQL Server to be 'dbo'.
|
1547
1588
|
if (::Brick.is_oracle && r[0] != schema) || (is_mssql && r[0] != 'dbo')
|
@@ -1668,7 +1709,7 @@ ORDER BY 1, 2, c.internal_column_id, acc.position"
|
|
1668
1709
|
name_parts = k.split('.')
|
1669
1710
|
idx = 1
|
1670
1711
|
name_parts = name_parts.map do |x|
|
1671
|
-
(idx += 1)
|
1712
|
+
(idx += 1) <= name_parts.length ? x : x.singularize
|
1672
1713
|
end
|
1673
1714
|
name_parts.shift if apartment && name_parts.length > 1 && name_parts.first == Apartment.default_schema
|
1674
1715
|
class_name = name_parts.map(&:camelize).join('::')
|
@@ -1696,7 +1737,7 @@ ORDER BY 1, 2, c.internal_column_id, acc.position"
|
|
1696
1737
|
def display_classes(rels, max_length)
|
1697
1738
|
rels.sort.each do |rel|
|
1698
1739
|
rel_link = rel.last.dup.map(&:underscore)
|
1699
|
-
rel_link[-1] = rel_link[-1]
|
1740
|
+
rel_link[-1] = rel_link[-1]
|
1700
1741
|
puts "#{rel.first}#{' ' * (max_length - rel.first.length)} /#{rel_link.join('/')}"
|
1701
1742
|
end
|
1702
1743
|
puts "\n"
|
@@ -1706,8 +1747,11 @@ ORDER BY 1, 2, c.internal_column_id, acc.position"
|
|
1706
1747
|
is_mssql = ActiveRecord::Base.connection.adapter_name == 'SQLServer' if is_mssql.nil?
|
1707
1748
|
sql ||= "SELECT t.table_schema AS \"schema\", t.table_name AS relation_name, t.table_type,#{"
|
1708
1749
|
pg_catalog.obj_description(
|
1709
|
-
('\"' || t.table_schema || '\".\"' || t.table_name || '\"')::regclass, 'pg_class'
|
1710
|
-
) AS table_description,
|
1750
|
+
('\"' || t.table_schema || '\".\"' || t.table_name || '\"')::regclass::oid, 'pg_class'
|
1751
|
+
) AS table_description,
|
1752
|
+
pg_catalog.col_description(
|
1753
|
+
('\"' || t.table_schema || '\".\"' || t.table_name || '\"')::regclass::oid, c.ordinal_position
|
1754
|
+
) AS column_description," if is_postgres}
|
1711
1755
|
c.column_name, c.data_type,
|
1712
1756
|
COALESCE(c.character_maximum_length, c.numeric_precision) AS max_length,
|
1713
1757
|
kcu.constraint_type AS const, kcu.constraint_name AS \"key\",
|
@@ -1751,6 +1795,43 @@ ORDER BY 1, 2, c.internal_column_id, acc.position"
|
|
1751
1795
|
ar_imtn = ActiveRecord.version >= ::Gem::Version.new('5.0') ? ActiveRecord::Base.internal_metadata_table_name : ''
|
1752
1796
|
[ar_smtn, ar_imtn]
|
1753
1797
|
end
|
1798
|
+
|
1799
|
+
def apply_double_underscore_patch
|
1800
|
+
unless @double_underscore_applied
|
1801
|
+
# Same as normal #camelize and #underscore, just that double-underscores turn into a single underscore
|
1802
|
+
ActiveSupport::Inflector.class_eval do
|
1803
|
+
def camelize(term, uppercase_first_letter = true)
|
1804
|
+
strings = term.to_s.split('__').map do |string|
|
1805
|
+
# String#camelize takes a symbol (:upper or :lower), so here we also support :lower to keep the methods consistent.
|
1806
|
+
if !uppercase_first_letter || uppercase_first_letter == :lower
|
1807
|
+
string = string.sub(inflections.acronyms_camelize_regex) { |match| match.downcase! || match }
|
1808
|
+
else
|
1809
|
+
string = string.sub(/^[a-z\d]*/) { |match| inflections.acronyms[match] || match.capitalize! || match }
|
1810
|
+
end
|
1811
|
+
string.gsub!(/(?:_|(\/))([a-z\d]*)/i) do
|
1812
|
+
word = $2
|
1813
|
+
substituted = inflections.acronyms[word] || word.capitalize! || word
|
1814
|
+
$1 ? "::#{substituted}" : substituted
|
1815
|
+
end
|
1816
|
+
string
|
1817
|
+
end
|
1818
|
+
strings.join('_')
|
1819
|
+
end
|
1820
|
+
|
1821
|
+
def underscore(camel_cased_word)
|
1822
|
+
return camel_cased_word.to_s unless /[A-Z-]|::/.match?(camel_cased_word)
|
1823
|
+
camel_cased_word.to_s.gsub("::", "/").split('_').map do |word|
|
1824
|
+
word.gsub!(inflections.acronyms_underscore_regex) { "#{$1 && '_' }#{$2.downcase}" }
|
1825
|
+
word.gsub!(/([A-Z]+)(?=[A-Z][a-z])|([a-z\d])(?=[A-Z])/) { ($1 || $2) << "_" }
|
1826
|
+
word.tr!("-", "_")
|
1827
|
+
word.downcase!
|
1828
|
+
word
|
1829
|
+
end.join('__')
|
1830
|
+
end
|
1831
|
+
end
|
1832
|
+
@double_underscore_applied = true
|
1833
|
+
end
|
1834
|
+
end
|
1754
1835
|
end
|
1755
1836
|
|
1756
1837
|
# ==========================================
|
@@ -1777,7 +1858,7 @@ module Brick
|
|
1777
1858
|
|
1778
1859
|
class << self
|
1779
1860
|
def _add_bt_and_hm(fk, relations, is_polymorphic = false, is_optional = false)
|
1780
|
-
bt_assoc_name = ::Brick.namify(fk[2],
|
1861
|
+
bt_assoc_name = ::Brick.namify(fk[2], :downcase)
|
1781
1862
|
unless is_polymorphic
|
1782
1863
|
bt_assoc_name = if bt_assoc_name.underscore.end_with?('_id')
|
1783
1864
|
bt_assoc_name[-3] == '_' ? bt_assoc_name[0..-4] : bt_assoc_name[0..-3]
|
@@ -1878,6 +1959,11 @@ module Brick
|
|
1878
1959
|
|
1879
1960
|
return if is_class || ::Brick.config.exclude_hms&.any? { |exclusion| fk[1] == exclusion[0] && fk[2] == exclusion[1] && primary_table == exclusion[2] } || hms.nil?
|
1880
1961
|
|
1962
|
+
# if fk[1].end_with?('Suppliers') && fk[4] == 'People'
|
1963
|
+
# puts fk.inspect
|
1964
|
+
# binding.pry
|
1965
|
+
# end
|
1966
|
+
|
1881
1967
|
if (assoc_hm = hms.fetch((hm_cnstr_name = "hm_#{cnstr_name}"), nil))
|
1882
1968
|
if assoc_hm[:fk].is_a?(String)
|
1883
1969
|
assoc_hm[:fk] = [assoc_hm[:fk], fk[2]] unless fk[2] == assoc_hm[:fk]
|
@@ -1885,7 +1971,6 @@ module Brick
|
|
1885
1971
|
assoc_hm[:fk] << fk[2]
|
1886
1972
|
end
|
1887
1973
|
assoc_hm[:alternate_name] = "#{assoc_hm[:alternate_name]}_#{bt_assoc_name}" unless assoc_hm[:alternate_name] == bt_assoc_name
|
1888
|
-
assoc_hm[:inverse] = assoc_bt
|
1889
1974
|
else
|
1890
1975
|
inv_tbl = if ::Brick.config.schema_behavior[:multitenant] && apartment && fk[0] == Apartment.default_schema
|
1891
1976
|
for_tbl
|
@@ -1896,7 +1981,7 @@ module Brick
|
|
1896
1981
|
inverse_table: inv_tbl, inverse: assoc_bt }
|
1897
1982
|
assoc_hm[:polymorphic] = true if is_polymorphic
|
1898
1983
|
hm_counts = relation.fetch(:hm_counts) { relation[:hm_counts] = {} }
|
1899
|
-
hm_counts[fk[1]] = hm_counts.fetch(fk[1]) { 0 } + 1
|
1984
|
+
this_hm_count = hm_counts[fk[1]] = hm_counts.fetch(fk[1]) { 0 } + 1
|
1900
1985
|
end
|
1901
1986
|
assoc_bt[:inverse] = assoc_hm
|
1902
1987
|
end
|
@@ -159,7 +159,7 @@ module Brick
|
|
159
159
|
hms_columns << hm_entry
|
160
160
|
when 'show', 'new', 'update'
|
161
161
|
hm_stuff << if hm_fk_name
|
162
|
-
"<%= link_to '#{assoc_name}', #{hm_assoc.klass.
|
162
|
+
"<%= link_to '#{assoc_name}', #{hm_assoc.klass._brick_index}_path({ #{path_keys(hm_assoc, hm_fk_name, "@#{obj_name}", pk)} }) %>\n"
|
163
163
|
else # %%% Would be able to remove this when multiple foreign keys to same destination becomes bulletproof
|
164
164
|
assoc_name
|
165
165
|
end
|
@@ -173,12 +173,13 @@ module Brick
|
|
173
173
|
# environment or whatever, then get either the controllers or routes list instead
|
174
174
|
apartment_default_schema = ::Brick.apartment_multitenant && Apartment.default_schema
|
175
175
|
table_options = (::Brick.relations.keys - ::Brick.config.exclude_tables).each_with_object({}) do |tbl, s|
|
176
|
+
binding.pry if tbl.is_a?(Symbol)
|
176
177
|
if (tbl_parts = tbl.split('.')).first == apartment_default_schema
|
177
178
|
tbl = tbl_parts.last
|
178
179
|
end
|
179
180
|
s[tbl] = nil
|
180
181
|
end.keys.sort.each_with_object(+'') do |v, s|
|
181
|
-
s << "<option value=\"#{v.underscore.gsub('.', '/')
|
182
|
+
s << "<option value=\"#{v.underscore.gsub('.', '/')}\">#{v}</option>"
|
182
183
|
end.html_safe
|
183
184
|
table_options << '<option value="brick_status">(Status)</option>'.html_safe if ::Brick.config.add_status
|
184
185
|
table_options << '<option value="brick_orphans">(Orphans)</option>'.html_safe if is_orphans
|
@@ -351,15 +352,39 @@ def hide_bcrypt(val, max_len = 200)
|
|
351
352
|
end
|
352
353
|
def display_value(col_type, val)
|
353
354
|
case col_type
|
354
|
-
when 'geometry'
|
355
|
+
when 'geometry', 'geography'
|
355
356
|
if Object.const_defined?('RGeo')
|
356
357
|
@is_mysql = ActiveRecord::Base.connection.adapter_name == 'Mysql2' if @is_mysql.nil?
|
357
|
-
if @
|
358
|
-
|
359
|
-
|
360
|
-
|
358
|
+
@is_mssql = ActiveRecord::Base.connection.adapter_name == 'SQLServer' if @is_mssql.nil?
|
359
|
+
val_err = nil
|
360
|
+
if @is_mysql || @is_mssql
|
361
|
+
# MySQL's \"Internal Geometry Format\" and MSSQL's Geography are like WKB, but with an initial 4 bytes that indicates the SRID.
|
362
|
+
if (srid = val&.[](0..3)&.unpack('I'))
|
363
|
+
val = val.force_encoding('BINARY')[4..-1].bytes
|
364
|
+
|
365
|
+
# MSSQL spatial bitwise flags, often 0C for a point:
|
366
|
+
# xxxx xxx1 = HasZValues
|
367
|
+
# xxxx xx1x = HasMValues
|
368
|
+
# xxxx x1xx = IsValid
|
369
|
+
# xxxx 1xxx = IsSinglePoint
|
370
|
+
# xxx1 xxxx = IsSingleLineSegment
|
371
|
+
# xx1x xxxx = IsWholeGlobe
|
372
|
+
# Convert Microsoft's unique geography binary to standard WKB
|
373
|
+
# (MSSQL point usually has two doubles, lng / lat, and can also have Z)
|
374
|
+
if @is_mssql
|
375
|
+
if val[0] == 1 && (val[1] & 8 > 0) && # Single point?
|
376
|
+
(val.length - 2) % 8 == 0 && val.length < 27 # And containing up to three 8-byte values?
|
377
|
+
idx = 2
|
378
|
+
new_val = [0, 0, 0, 0, 1]
|
379
|
+
new_val.concat(val[idx - 8...idx].reverse) while (idx += 8) <= val.length
|
380
|
+
val = new_val
|
381
|
+
else
|
382
|
+
val_err = '(Microsoft internal SQL geography type)'
|
383
|
+
end
|
384
|
+
end
|
385
|
+
end
|
361
386
|
end
|
362
|
-
RGeo::WKRep::WKBParser.new.parse(val)
|
387
|
+
val_err || (val ? RGeo::WKRep::WKBParser.new.parse(val.pack('c*')) : nil)
|
363
388
|
else
|
364
389
|
'(Add RGeo gem to parse geometry detail)'
|
365
390
|
end
|
@@ -448,7 +473,7 @@ function changeout(href, param, value, trimAfter) {
|
|
448
473
|
var params = hrefParts.length > 1 ? hrefParts[1].split(\"&\") : [];
|
449
474
|
if (param === undefined || param === null || param === -1) {
|
450
475
|
hrefParts = hrefParts[0].split(\"://\");
|
451
|
-
var pathParts = hrefParts[hrefParts.length - 1].split(\"/\");
|
476
|
+
var pathParts = hrefParts[hrefParts.length - 1].split(\"/\").filter(function (pp) {return pp !== \"\";});
|
452
477
|
if (value === undefined)
|
453
478
|
// A couple possibilities if it's namespaced, starting with two parts in the path -- and then try just one
|
454
479
|
return [pathParts.slice(1, 3).join('/'), pathParts.slice(1, 2)[0]];
|
@@ -562,7 +587,7 @@ erDiagram
|
|
562
587
|
<%= \"#\{model_short_name} }o..o{ #\{hm_name} : \\\"#\{hm.first}\\\"\".html_safe %><%
|
563
588
|
else # has_many
|
564
589
|
%> <%= \"#\{model_short_name} ||--o{ #\{hm_name} : \\\"#\{
|
565
|
-
|
590
|
+
hm.first.to_s unless hm.first.to_s.downcase == hm_class.name.underscore.pluralize.tr('/', '_')
|
566
591
|
}\\\"\".html_safe %><%
|
567
592
|
end %>
|
568
593
|
<% end
|
@@ -604,7 +629,7 @@ erDiagram
|
|
604
629
|
end
|
605
630
|
if Object.const_defined?('DutyFree')
|
606
631
|
template_link = "
|
607
|
-
<%= link_to 'CSV', #{
|
632
|
+
<%= link_to 'CSV', #{@_brick_model._brick_index}_path(format: :csv) %> <a href=\"#\" id=\"sheetsLink\">Sheets</a>
|
608
633
|
<div id=\"dropper\" contenteditable=\"true\"></div>
|
609
634
|
<input type=\"button\" id=\"btnImport\" value=\"Import\">
|
610
635
|
|
@@ -667,7 +692,7 @@ erDiagram
|
|
667
692
|
console.log(\"x1\", sheetUrl);
|
668
693
|
|
669
694
|
// Get JSON data
|
670
|
-
fetch(changeout(<%= #{
|
695
|
+
fetch(changeout(<%= #{@_brick_model._brick_index}_path(format: :js).inspect.html_safe %>, \"_brick_schema\", brickSchema)).then(function (response) {
|
671
696
|
response.json().then(function (data) {
|
672
697
|
gapi.client.sheets.spreadsheets.values.append({
|
673
698
|
spreadsheetId: spreadsheetId,
|
@@ -698,7 +723,7 @@ erDiagram
|
|
698
723
|
<select id=\"schema\">#{schema_options}</select>" if ::Brick.config.schema_behavior[:multitenant] && ::Brick.db_schemas.length > 1}
|
699
724
|
<select id=\"tbl\">#{table_options}</select>
|
700
725
|
<table id=\"resourceName\"><tr>
|
701
|
-
<td><h1>#{
|
726
|
+
<td><h1>#{model_name}</h1></td>
|
702
727
|
<td id=\"imgErd\" title=\"Show ERD\"></td>
|
703
728
|
</tr></table>#{template_link}<%
|
704
729
|
if (description = (relation = Brick.relations[#{model_name}.table_name])&.fetch(:description, nil)) %><%=
|
@@ -712,10 +737,10 @@ erDiagram
|
|
712
737
|
origin = (key_parts = k.split('.')).length == 1 ? #{model_name} : #{model_name}.reflect_on_association(key_parts.first).klass
|
713
738
|
if (destination_fk = Brick.relations[origin.table_name][:fks].values.find { |fk| fk[:fk] == key_parts.last }) &&
|
714
739
|
(obj = (destination = origin.reflect_on_association(destination_fk[:assoc_name])&.klass)&.find(id)) %>
|
715
|
-
<h3>for <%= link_to \"#{"#\{obj.brick_descrip\} (#\{destination.name\})\""}, send(\"#\{destination.
|
740
|
+
<h3>for <%= link_to \"#{"#\{obj.brick_descrip\} (#\{destination.name\})\""}, send(\"#\{destination._brick_index\}_path\".to_sym, id) %></h3><%
|
716
741
|
end
|
717
742
|
end %>
|
718
|
-
(<%= link_to 'See all #{
|
743
|
+
(<%= link_to 'See all #{model_name.split('::').last.pluralize}', #{@_brick_model._brick_index}_path %>)
|
719
744
|
<% end
|
720
745
|
# COLUMN EXCLUSIONS
|
721
746
|
if @_brick_excl&.present? %>
|
@@ -768,7 +793,7 @@ erDiagram
|
|
768
793
|
end
|
769
794
|
elsif col # HM column
|
770
795
|
s << \"<th#\{' x-order=\"' + col_name + '\"' if true}>#\{col[2]} \"
|
771
|
-
s << (col.first ? \"#\{col[3]}\" : \"#\{link_to(col[3], send(\"#\{col[1].
|
796
|
+
s << (col.first ? \"#\{col[3]}\" : \"#\{link_to(col[3], send(\"#\{col[1]._brick_index}_path\"))}\")
|
772
797
|
else # Bad column name!
|
773
798
|
s << \"<th title=\\\"<< Unknown column >>\\\">#\{col_name}\"
|
774
799
|
end
|
@@ -776,7 +801,11 @@ erDiagram
|
|
776
801
|
end.html_safe
|
777
802
|
%></tr></thead>
|
778
803
|
<tbody>
|
779
|
-
<%
|
804
|
+
<% # %%% Have once gotten this error with MSSQL referring to http://localhost:3000/warehouse/cold_room_temperatures__archive
|
805
|
+
# ActiveRecord::StatementTimeout in Warehouse::ColdRoomTemperatures_Archive#index
|
806
|
+
# TinyTds::Error: Adaptive Server connection timed out
|
807
|
+
# (After restarting the server it worked fine again.)
|
808
|
+
@#{table_name}.each do |#{obj_name}|
|
780
809
|
hms_cols = {#{hms_columns.join(', ')}} %>
|
781
810
|
<tr>#{"
|
782
811
|
<td><%= link_to '⇛', #{path_obj_name}_path(#{obj_pk}), { class: 'big-arrow' } %></td>" if obj_pk}
|
@@ -811,10 +840,11 @@ erDiagram
|
|
811
840
|
else
|
812
841
|
\"#\{hms_col[1] || 'View'\} #\{hms_col.first}\"
|
813
842
|
end %>
|
814
|
-
<%= link_to txt, send(\"#\{klass.
|
843
|
+
<%= link_to txt, send(\"#\{klass._brick_index}_path\".to_sym, hms_col[2]) unless hms_col[1]&.zero? %>
|
815
844
|
<% end
|
816
845
|
elsif (col = cols[col_name])
|
817
|
-
|
846
|
+
col_type = col&.sql_type == 'geography' ? col.sql_type : col&.type
|
847
|
+
%><%= display_value(col_type || col&.sql_type, val) %><%
|
818
848
|
else # Bad column name!
|
819
849
|
%>?<%
|
820
850
|
end
|
@@ -908,7 +938,7 @@ erDiagram
|
|
908
938
|
if (description = (relation = Brick.relations[#{model_name}.table_name])&.fetch(:description, nil)) %><%=
|
909
939
|
description %><br><%
|
910
940
|
end
|
911
|
-
%><%= link_to '(See all #{obj_name.pluralize})', #{
|
941
|
+
%><%= link_to '(See all #{obj_name.pluralize})', #{@_brick_model._brick_index}_path %>
|
912
942
|
#{erd_markup}
|
913
943
|
<% if obj %>
|
914
944
|
<br><br>
|
@@ -974,7 +1004,8 @@ end
|
|
974
1004
|
\"<span class=\\\"orphan\\\">Orphaned ID: #\{val}</span>\".html_safe
|
975
1005
|
end %>
|
976
1006
|
<% else
|
977
|
-
|
1007
|
+
col_type = col.sql_type == 'geography' ? col.sql_type : col.type
|
1008
|
+
case (col_type ||= col.sql_type)
|
978
1009
|
when :string, :text %>
|
979
1010
|
<% if is_bcrypt?(val) # || .readonly?
|
980
1011
|
is_revert = false %>
|
@@ -1008,8 +1039,8 @@ end
|
|
1008
1039
|
<% when :binary, :primary_key
|
1009
1040
|
is_revert = false %>
|
1010
1041
|
<% else %>
|
1011
|
-
<%=
|
1012
|
-
|
1042
|
+
<%= is_revert = false
|
1043
|
+
display_value(col_type, val) %>
|
1013
1044
|
<% end
|
1014
1045
|
end
|
1015
1046
|
if is_revert
|
@@ -1077,7 +1108,7 @@ flatpickr(\".timepicker\", {enableTime: true, noCalendar: true});
|
|
1077
1108
|
var imgErd = document.getElementById(\"imgErd\");
|
1078
1109
|
var mermaidErd = document.getElementById(\"mermaidErd\");
|
1079
1110
|
var mermaidCode;
|
1080
|
-
var cbs = {<%= callbacks.map { |k, v| \"#\{k}: \\\"#\{v.
|
1111
|
+
var cbs = {<%= callbacks.map { |k, v| \"#\{k}: \\\"#\{send(\"#\{v._brick_index}_path\".to_sym)}\\\"\" }.join(', ').html_safe %>};
|
1081
1112
|
if (imgErd) imgErd.addEventListener(\"click\", showErd);
|
1082
1113
|
function showErd() {
|
1083
1114
|
imgErd.style.display = \"none\";
|
@@ -1101,7 +1132,7 @@ flatpickr(\".timepicker\", {enableTime: true, noCalendar: true});
|
|
1101
1132
|
function (evt) {
|
1102
1133
|
location.href = changeout(changeout(
|
1103
1134
|
changeout(location.href, '_brick_order', null), // Remove any ordering
|
1104
|
-
-1, cbs[this.id]), \"_brick_erd\", \"1\");
|
1135
|
+
-1, cbs[this.id].replace(/^[\/]+/, \"\")), \"_brick_erd\", \"1\");
|
1105
1136
|
}
|
1106
1137
|
);
|
1107
1138
|
}
|
data/lib/brick/version_number.rb
CHANGED
data/lib/brick.rb
CHANGED
@@ -125,8 +125,8 @@ module Brick
|
|
125
125
|
class << self
|
126
126
|
attr_accessor :default_schema, :db_schemas, :routes_done, :is_oracle
|
127
127
|
|
128
|
-
def set_db_schema(params)
|
129
|
-
schema = params['_brick_schema'] || 'public'
|
128
|
+
def set_db_schema(params = nil)
|
129
|
+
schema = (params ? params['_brick_schema'] : ::Brick.default_schema) || 'public'
|
130
130
|
if schema && ::Brick.db_schemas&.include?(schema)
|
131
131
|
ActiveRecord::Base.execute_sql("SET SEARCH_PATH = ?;", schema)
|
132
132
|
schema
|
@@ -152,17 +152,19 @@ module Brick
|
|
152
152
|
end
|
153
153
|
|
154
154
|
# Convert spaces to underscores if the second character and onwards is mixed case
|
155
|
-
def namify(name,
|
156
|
-
|
155
|
+
def namify(name, action = nil)
|
156
|
+
has_uppers = name =~ /[A-Z]+/
|
157
|
+
has_lowers = name =~ /[a-z]+/
|
158
|
+
name.downcase! if has_uppers && action == :downcase
|
157
159
|
if name.include?(' ')
|
158
160
|
# All uppers or all lowers?
|
159
|
-
if
|
161
|
+
if !has_uppers || !has_lowers
|
160
162
|
name.titleize.tr(' ', '_')
|
161
163
|
else # Mixed uppers and lowers -- just remove existing spaces
|
162
164
|
name.tr(' ', '')
|
163
165
|
end
|
164
166
|
else
|
165
|
-
name
|
167
|
+
action == :underscore ? name.underscore : name
|
166
168
|
end
|
167
169
|
end
|
168
170
|
|
@@ -266,6 +268,26 @@ module Brick
|
|
266
268
|
!!Brick.config.enable_routes
|
267
269
|
end
|
268
270
|
|
271
|
+
# @api public
|
272
|
+
def enable_api=(path)
|
273
|
+
Brick.config.enable_api = path
|
274
|
+
end
|
275
|
+
|
276
|
+
# @api public
|
277
|
+
def enable_api
|
278
|
+
Brick.config.enable_api
|
279
|
+
end
|
280
|
+
|
281
|
+
# @api public
|
282
|
+
def api_root=(path)
|
283
|
+
Brick.config.api_root = path
|
284
|
+
end
|
285
|
+
|
286
|
+
# @api public
|
287
|
+
def api_root
|
288
|
+
Brick.config.api_root
|
289
|
+
end
|
290
|
+
|
269
291
|
# @api public
|
270
292
|
def skip_database_views=(value)
|
271
293
|
Brick.config.skip_database_views = value
|
@@ -484,7 +506,7 @@ In config/initializers/brick.rb appropriate entries would look something like:
|
|
484
506
|
# %%% TODO: If no auto-controllers then enumerate the controllers folder in order to build matching routes
|
485
507
|
# If auto-controllers and auto-models are both enabled then this makes sense:
|
486
508
|
::Brick.relations.each do |rel_name, v|
|
487
|
-
rel_name = rel_name.split('.').map { |
|
509
|
+
rel_name = rel_name.split('.').map { |rel_part| ::Brick.namify(rel_part, :underscore) }
|
488
510
|
schema_names = rel_name[0..-2]
|
489
511
|
schema_names.shift if ::Brick.apartment_multitenant && schema_names.first == Apartment.default_schema
|
490
512
|
# %%% If more than one schema has the same table name, will need to add a schema name prefix to have uniqueness
|
@@ -494,10 +516,12 @@ In config/initializers/brick.rb appropriate entries would look something like:
|
|
494
516
|
options[:only] = [:index, :show] if v.key?(:isView)
|
495
517
|
if schema_names.present? # && !Object.const_defined('Apartment')
|
496
518
|
send(:namespace, schema_names.first) do
|
497
|
-
send(:resources,
|
519
|
+
send(:resources, k.to_sym, **options)
|
498
520
|
end
|
521
|
+
send(:get, "/api/v1/#{schema_names.first}/#{k}", { to: "#{schema_names.first}/#{controller_name}#index" }) if Object.const_defined?('Rswag::Ui')
|
499
522
|
else
|
500
|
-
send(:resources,
|
523
|
+
send(:resources, k.to_sym, **options)
|
524
|
+
send(:get, "/api/v1/#{k}", { to: "#{controller_name}#index" }) if Object.const_defined?('Rswag::Ui')
|
501
525
|
end
|
502
526
|
end
|
503
527
|
if ::Brick.config.add_status && instance_variable_get(:@set).named_routes.names.exclude?(:brick_status)
|
@@ -507,7 +531,11 @@ In config/initializers/brick.rb appropriate entries would look something like:
|
|
507
531
|
get('/brick_orphans', to: 'brick_gem#orphans', as: 'brick_orphans')
|
508
532
|
end
|
509
533
|
end
|
510
|
-
|
534
|
+
if Object.const_defined?('Rswag::Ui') && doc_endpoint = Rswag::Ui.config.config_object[:urls].last
|
535
|
+
# Serves JSON swagger info from a path such as '/api-docs/v1/swagger.json'
|
536
|
+
puts "Mounting swagger info endpoint for \"#{doc_endpoint[:name]}\" on #{doc_endpoint[:url]}"
|
537
|
+
send(:get, doc_endpoint[:url], { to: 'brick_swagger#index' })
|
538
|
+
end
|
511
539
|
end
|
512
540
|
super
|
513
541
|
end
|
@@ -147,6 +147,8 @@ module Brick
|
|
147
147
|
# Brick.enable_controllers = true # Setting this to \"false\" will disable controllers in development
|
148
148
|
# Brick.enable_views = true # Setting this to \"false\" will disable views in development
|
149
149
|
|
150
|
+
# Brick.api_root = '/api/v1/' # Path from which to serve out API resources when the RSwag gem is present
|
151
|
+
|
150
152
|
# # By default models are auto-created for database views, and set to be read-only. This can be skipped.
|
151
153
|
# Brick.skip_database_views = true
|
152
154
|
|
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.73
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lorin Thwaits
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-09-
|
11
|
+
date: 2022-09-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|