brick 1.0.89 → 1.0.91

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a94d71d50a84c847db5f2c34e5aba600502ecb60d4dc7752dc65ac21f4ffe41b
4
- data.tar.gz: 6f337f6220cf5989669497e85da0d4620861b1be6e4a35720a072698d866ebe2
3
+ metadata.gz: 81eaa518a99452286bdaf1e5ed33b83962ede9f9c6509f0b472fd0fe19a8eceb
4
+ data.tar.gz: 06f5653ce40eb6ee1568b380cf3063073ac7735add8aab6c5873a343e8018a70
5
5
  SHA512:
6
- metadata.gz: 703fa83ad63f9da5f4431c05db9fee57843419b62283f92f39b7b4cf9397848177f10f57af7fc03f08cf503a392676adac272a04fe4ae6becbf0e0a5eb62c550
7
- data.tar.gz: 686c752bd2ed92de4f12c4afe27389d8a6cced25b47c5a18564c5afdf51199bd148f66ec5636ee8094a0cda5ae1ccafce31bc532a9d7d6a64c4cc968013f6af3
6
+ metadata.gz: 7e0a678885c927a7a80c8758d265c2ff351f67ea44e8e1b2c128e123df441f4f72a62f775b9785615eeacbdbff99427e9d1590890bdffd06165ae7b2339fe1af
7
+ data.tar.gz: 7bd3e424225e435bab4517fb14aeaa3ca128041a746aaf413ecdb17a771444c3413f058ff28cc5e303d074fdd7cc7d21ff66f842667c14226d1849e96d4b3a98
@@ -127,13 +127,14 @@ module ActiveRecord
127
127
  if bracket_name
128
128
  if ch == ']' # Time to process a bracketed thing?
129
129
  parts = bracket_name.split('.')
130
- first_parts = parts[0..-2].map do |part|
131
- klass = (orig_class = klass).reflect_on_association(part_sym = part.to_sym)&.klass
132
- puts "Couldn't reference #{orig_class.name}##{part} that's part of the DSL \"#{dsl}\"." if klass.nil?
133
- part_sym
130
+ first_parts = parts[0..-2].each_with_object([]) do |part, s|
131
+ unless (klass = (orig_class = klass).reflect_on_association(part_sym = part.to_sym)&.klass)
132
+ puts "Couldn't reference #{orig_class.name}##{part} that's part of the DSL \"#{dsl}\"."
133
+ break
134
+ end
135
+ s << part_sym
134
136
  end
135
- parts = prefix + first_parts + [parts[-1]]
136
- if parts.length > 1
137
+ if (parts = prefix + first_parts + [parts[-1]]).length > 1 && klass
137
138
  unless is_polymorphic
138
139
  s = build_array
139
140
  parts[0..-3].each { |v| s = s[v.to_sym] }
@@ -141,7 +142,7 @@ module ActiveRecord
141
142
  end
142
143
  translations[parts[0..-2].join('.')] = klass
143
144
  end
144
- if klass.column_names.exclude?(parts.last) &&
145
+ if klass&.column_names.exclude?(parts.last) &&
145
146
  (klass = (orig_class = klass).reflect_on_association(possible_dsl = parts.pop.to_sym)&.klass)
146
147
  if prefix.empty? # Custom columns start with an empty prefix
147
148
  prefix << parts.shift until parts.empty?
@@ -308,9 +309,15 @@ module ActiveRecord
308
309
  def self._brick_calculate_bts_hms(translations, join_array)
309
310
  # Add any custom columns
310
311
  ::Brick.config.custom_columns&.fetch(table_name, nil)&.each do |k, cc|
312
+ if cc.is_a?(Array)
313
+ fk_col = cc.last unless cc.last.blank?
314
+ cc = cc.first
315
+ else
316
+ fk_col = true
317
+ end
311
318
  # false = not polymorphic, and true = yes -- please emit_dsl
312
319
  pieces, my_dsl = brick_parse_dsl(join_array, [], translations, false, cc, true)
313
- _br_cust_cols[k] = [pieces, my_dsl]
320
+ _br_cust_cols[k] = [pieces, my_dsl, fk_col]
314
321
  end
315
322
  bts, hms, associatives = ::Brick.get_bts_and_hms(self)
316
323
  bts.each do |_k, bt|
@@ -382,6 +389,23 @@ module ActiveRecord
382
389
  end
383
390
  end
384
391
 
392
+ module AttributeMethods
393
+ module ClassMethods
394
+ alias _brick_dangerous_attribute_method? dangerous_attribute_method?
395
+ # Bypass the error "ActiveRecord::DangerousAttributeError" if this object comes from a view.
396
+ # (Allows for column names such as 'attribute', 'delete', and 'update' to still work.)
397
+ def dangerous_attribute_method?(name)
398
+ if (is_dangerous = _brick_dangerous_attribute_method?(name)) && is_view?
399
+ if column_names.include?(name.to_s)
400
+ puts "WARNING: Column \"#{name}\" in view #{table_name} conflicts with a reserved ActiveRecord method name."
401
+ end
402
+ return false
403
+ end
404
+ is_dangerous
405
+ end
406
+ end
407
+ end
408
+
385
409
  class Relation
386
410
  attr_reader :_brick_chains, :_arel_applied_aliases
387
411
 
@@ -539,6 +563,10 @@ module ActiveRecord
539
563
  next
540
564
  end
541
565
 
566
+ key_klass = nil
567
+ key_tbl_name = nil
568
+ dest_pk = nil
569
+ key_alias = nil
542
570
  cc.first.each do |cc_part|
543
571
  dest_klass = cc_part[0..-2].inject(klass) { |kl, cc_part_term| kl.reflect_on_association(cc_part_term).klass }
544
572
  tbl_name = (field_tbl_names[k][cc_part.last] ||= shift_or_first(chains[dest_klass])).split('.').last
@@ -551,10 +579,29 @@ module ActiveRecord
551
579
  used_col_aliases.key?(col_alias)
552
580
  cc_part_idx -= 1
553
581
  end
582
+ used_col_aliases[col_alias] = nil
583
+ # Set up custom column links by preparing key_klass and key_alias
584
+ # (If there are multiple different tables referenced in the DSL, we end up creating a link to the last one)
585
+ if cc[2] && (dest_pk = dest_klass.primary_key)
586
+ key_klass = dest_klass
587
+ key_tbl_name = tbl_name
588
+ cc_part_idx = cc_part.length - 1
589
+ while cc_part_idx > 0 &&
590
+ (key_alias = "br_cc_#{k}__#{(cc_part[cc_part_idx..-2] + [dest_pk]).map(&:to_s).join('__')}") &&
591
+ key_alias != col_alias && # We break out if this key alias does exactly match the col_alias
592
+ used_col_aliases.key?(key_alias)
593
+ cc_part_idx -= 1
594
+ end
595
+ end
554
596
  selects << "#{tbl_name}.#{cc_part.last} AS #{col_alias}"
555
597
  cc_part << col_alias
556
- used_col_aliases[col_alias] = nil
557
598
  end
599
+ # Add a key column unless we've already got it
600
+ if key_alias && !used_col_aliases.key?(key_alias)
601
+ selects << "#{key_tbl_name}.#{dest_pk} AS #{key_alias}"
602
+ used_col_aliases[key_alias] = nil
603
+ end
604
+ cc[2] = key_alias ? [key_klass, key_alias] : nil
558
605
  end
559
606
 
560
607
  klass._br_bt_descrip.each do |v|
@@ -1058,7 +1105,7 @@ Module.class_exec do
1058
1105
  # elsif base_module != Object
1059
1106
  # module_parent.const_missing(*args)
1060
1107
  elsif Rails.respond_to?(:autoloaders) && # After finding nothing else, if Zeitwerk is enabled ...
1061
- (Rails::Autoloaders.respond_to?(:zeitwerk_enabled?) ? Rails::Autoloaders.zeitwerk_enabled? : true)
1108
+ (Rails::Autoloaders.respond_to?(:zeitwerk_enabled?) ? Rails::Autoloaders.zeitwerk_enabled? : true)
1062
1109
  self._brick_const_missing(*args) # ... rely solely on Zeitwerk.
1063
1110
  else # Classic mode
1064
1111
  unless (found = base_module._brick_const_missing(*args))
@@ -1149,7 +1196,7 @@ class Object
1149
1196
  if (base_model = ::Brick.sti_models[full_model_name]&.fetch(:base, nil) || ::Brick.existing_stis[full_model_name]&.constantize)
1150
1197
  is_sti = true
1151
1198
  else
1152
- base_model = ::Brick.config.models_inherit_from || ActiveRecord::Base
1199
+ base_model = ::Brick.config.models_inherit_from
1153
1200
  end
1154
1201
  hmts = nil
1155
1202
  code = +"class #{full_name} < #{base_model.name}\n"
@@ -1268,7 +1315,7 @@ class Object
1268
1315
  # hm.first[:inverse][:assoc_name].to_sym
1269
1316
  options[:source] = hm.last.to_sym
1270
1317
  else
1271
- through = hm.first[:alternate_name].pluralize
1318
+ through = hm.first.fetch(:alternate_chosen_name, hm.first[:alternate_name])
1272
1319
  end
1273
1320
  singular_assoc_name = hm.first[:inverse][:assoc_name].singularize
1274
1321
  "#{singular_assoc_name}_#{hmt_fk}"
@@ -1689,12 +1736,13 @@ class Object
1689
1736
  hm_assoc[:alternate_name] != (source || name.underscore)
1690
1737
  plural = "#{hm_assoc[:assoc_name]}_#{ActiveSupport::Inflector.pluralize(hm_assoc[:alternate_name])}"
1691
1738
  new_alt_name = (hm_assoc[:alternate_name] == name.underscore) ? "#{hm_assoc[:assoc_name].singularize}_#{plural}" : plural
1739
+ # %%% In rare cases might even need to add a number at the end for uniqueness
1692
1740
  # uniq = 1
1693
1741
  # while same_name = relation[:fks].find { |x| x.last[:assoc_name] == hm_assoc[:assoc_name] && x.last != hm_assoc }
1694
1742
  # hm_assoc[:assoc_name] = "#{hm_assoc_name}_#{uniq += 1}"
1695
1743
  # end
1696
1744
  # puts new_alt_name
1697
- # hm_assoc[:assoc_name] = new_alt_name
1745
+ hm_assoc[:alternate_chosen_name] = new_alt_name
1698
1746
  [new_alt_name, true]
1699
1747
  else
1700
1748
  assoc_name = ::Brick.namify(hm_assoc[:inverse_table]).pluralize
@@ -19,7 +19,12 @@ module Brick
19
19
  ::Brick.exclude_tables = app.config.brick.fetch(:exclude_tables, [])
20
20
 
21
21
  # Class for auto-generated models to inherit from
22
- ::Brick.models_inherit_from = app.config.brick.fetch(:models_inherit_from, ActiveRecord::Base)
22
+ ::Brick.models_inherit_from = app.config.brick.fetch(:models_inherit_from, nil) ||
23
+ begin
24
+ ::ApplicationRecord
25
+ rescue StandardError => ex
26
+ ::ActiveRecord::Base
27
+ end
23
28
 
24
29
  # When table names have specific prefixes, automatically place them in their own module with a table_name_prefix.
25
30
  ::Brick.table_name_prefixes = app.config.brick.fetch(:table_name_prefixes, [])
@@ -818,7 +823,16 @@ erDiagram
818
823
  end # DutyFree data export and import
819
824
  # %%% Instead of our current "for Janet Leverling (Employee)" kind of link we previously had this code that did a "where x = 123" thing:
820
825
  # (where <%= @_brick_params.each_with_object([]) { |v, s| s << \"#\{v.first\} = #\{v.last.inspect\}\" }.join(', ') %>)
821
- +"#{css}
826
+ +"<html>
827
+ <head>
828
+ #{css}
829
+ <title>#{model_name} <%
830
+ if (description = (relation = Brick.relations[#{model_name}.table_name])&.fetch(:description, nil)).present?
831
+ %> - <%= description
832
+ %><% end
833
+ %></title>
834
+ </head>
835
+ <body>
822
836
  <p style=\"color: green\"><%= notice %></p>#{"
823
837
  <select id=\"schema\">#{schema_options}</select>" if ::Brick.config.schema_behavior[:multitenant] && ::Brick.db_schemas.length > 1}
824
838
  <select id=\"tbl\">#{table_options}</select>
@@ -826,7 +840,7 @@ erDiagram
826
840
  <td><h1>#{model_name}</h1></td>
827
841
  <td id=\"imgErd\" title=\"Show ERD\"></td>
828
842
  </tr></table>#{template_link}<%
829
- if (description = (relation = Brick.relations[#{model_name}.table_name])&.fetch(:description, nil)).present? %><%=
843
+ if description.present? %><%=
830
844
  description %><br><%
831
845
  end
832
846
  # FILTER PARAMETERS
@@ -976,7 +990,12 @@ erDiagram
976
990
  %><%= display_value(col_type || col&.sql_type, val) %><%
977
991
  elsif cust_col
978
992
  data = cust_col.first.map { |cc_part| #{obj_name}.send(cc_part.last) }
979
- %><%= #{model_name}.brick_descrip(cust_col.last, data) %><%
993
+ cust_txt = #{model_name}.brick_descrip(cust_col[-2], data)
994
+ if (link_id = #{obj_name}.send(cust_col.last[1]) if cust_col.last)
995
+ %><%= link_to(cust_txt, send(\"#\{cust_col.last.first._brick_index(:singular)}_path\", link_id)) %><%
996
+ else
997
+ %><%= cust_txt %><%
998
+ end
980
999
  else # Bad column name!
981
1000
  %>?<%
982
1001
  end
@@ -988,7 +1007,10 @@ erDiagram
988
1007
  </table>
989
1008
 
990
1009
  #{"<hr><%= link_to \"New #{obj_name}\", new_#{path_obj_name}_path %>" unless @_brick_model.is_view?}
991
- #{script}"
1010
+ #{script}
1011
+ </body>
1012
+ </html>
1013
+ "
992
1014
 
993
1015
  when 'status'
994
1016
  if is_status
@@ -1061,7 +1083,14 @@ erDiagram
1061
1083
  end
1062
1084
 
1063
1085
  when 'show', 'new', 'update'
1064
- +"#{css}
1086
+ +"<html>
1087
+ <head>
1088
+ #{css}
1089
+ <title><%=
1090
+ page_title = (\"#{model_name}: #\{(obj = @#{obj_name})&.brick_descrip || controller_name}\")
1091
+ %></title>
1092
+ </head>
1093
+ <body>
1065
1094
 
1066
1095
  <svg id=\"revertTemplate\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"
1067
1096
  width=\"32px\" height=\"32px\" viewBox=\"0 0 512 512\" xml:space=\"preserve\">
@@ -1072,7 +1101,7 @@ erDiagram
1072
1101
  <p style=\"color: green\"><%= notice %></p>#{"
1073
1102
  <select id=\"schema\">#{schema_options}</select>" if ::Brick.config.schema_behavior[:multitenant] && ::Brick.db_schemas.length > 1}
1074
1103
  <select id=\"tbl\">#{table_options}</select>
1075
- <h1>#{model_name}: <%= (obj = @#{obj_name})&.brick_descrip || controller_name %></h1><%
1104
+ <h1><%= page_title %></h1><%
1076
1105
  if (description = (relation = Brick.relations[#{model_name}.table_name])&.fetch(:description, nil)) %><%=
1077
1106
  description %><br><%
1078
1107
  end
@@ -1236,7 +1265,10 @@ end
1236
1265
  "<%= button_to(\"Delete #\{@#{obj_name}.brick_descrip}\", send(\"#\{#{model_name}._brick_index(:singular)}_path\".to_sym, @#{obj_name}), { method: 'delete', class: 'danger', #{confirm_are_you_sure} }) %>"
1237
1266
  end}
1238
1267
  <% end %>
1239
- #{script}"
1268
+ #{script}
1269
+ </body>
1270
+ </html>
1271
+ "
1240
1272
 
1241
1273
  end
1242
1274
  inline << "
@@ -5,7 +5,7 @@ module Brick
5
5
  module VERSION
6
6
  MAJOR = 1
7
7
  MINOR = 0
8
- TINY = 89
8
+ TINY = 91
9
9
 
10
10
  # PRE is nil unless it's a pre-release (beta, RC, etc.)
11
11
  PRE = nil
data/lib/brick.rb CHANGED
@@ -186,10 +186,10 @@ module Brick
186
186
 
187
187
  def get_bts_and_hms(model)
188
188
  bts, hms = model.reflect_on_all_associations.each_with_object([{}, {}]) do |a, s|
189
- next if !a.polymorphic? && (a.klass.nil? || ::Brick.config.exclude_tables.include?(a.klass.table_name))
189
+ next unless a.polymorphic? || (!a.belongs_to? && (through = a.options[:through])) ||
190
+ (a.klass && ::Brick.config.exclude_tables.exclude?(a.klass.table_name))
190
191
 
191
- case a.macro
192
- when :belongs_to
192
+ if a.belongs_to?
193
193
  if a.polymorphic?
194
194
  rel_poly_bt = relations[model.table_name][:fks].find { |_k, fk| fk[:assoc_name] == a.name.to_s }
195
195
  if (primary_tables = rel_poly_bt&.last&.fetch(:inverse_table, [])).is_a?(Array)
@@ -205,8 +205,24 @@ module Brick
205
205
  else
206
206
  s.first[a.foreign_key.to_s] = [a.name, a.klass]
207
207
  end
208
- when :has_many, :has_one # This gets has_many as well as has_many :through
209
- # %%% weed out ones that don't have an available model to reference
208
+ else # This gets has_many as well as has_one and has_many :through
209
+ if through
210
+ is_invalid_source = nil
211
+ begin
212
+ if a.through_reflection&.belongs_to?
213
+ puts "WARNING: HMT relationship :#{a.name} in model #{model.name} tries to go through belongs_to association :#{through}. This is not possible."
214
+ next
215
+ elsif !a.source_reflection # Had considered: a.active_record.reflect_on_association(a.source_reflection_name).nil?
216
+ is_invalid_source = true
217
+ end
218
+ rescue
219
+ is_invalid_source = true
220
+ end
221
+ if is_invalid_source
222
+ puts "WARNING: HMT relationship :#{a.name} in model #{model.name} has invalid source :#{a.source_reflection_name}."
223
+ next
224
+ end
225
+ end
210
226
  s.last[a.name] = a
211
227
  end
212
228
  end
@@ -216,13 +232,10 @@ module Brick
216
232
  hms.each do |hmt|
217
233
  if (through = hmt.last.options[:through])
218
234
  # ::Brick.relations[hmt.last.through_reflection.table_name]
219
- skip_hms[through] = nil if hms[through] && model.is_brick?
235
+ skip_hms[through] = nil if hms[through] && model.is_brick? &&
236
+ hmt.last.klass != hmt.last.active_record # Don't pull HMs for HMTs that point back to the same table
220
237
  # End up with a hash of HMT names pointing to join-table associations
221
238
  model._br_associatives[hmt.first] = hms[through] # || hms["#{(opt = hmt.last.options)[:through].to_s.singularize}_#{opt[:source].to_s.pluralize}".to_sym]
222
- elsif hmt.last.inverse_of.nil? && ActiveRecord.version >= ::Gem::Version.new('4.2')
223
- puts "SKIPPING #{hmt.last.name.inspect}"
224
- # %%% If we don't do this then below associative.name will find that associative is nil
225
- skip_hms[hmt.last.name] = nil
226
239
  end
227
240
  end
228
241
  skip_hms.each { |k, _v| hms.delete(k) }
@@ -139,7 +139,7 @@ module Brick
139
139
  # Settings for the Brick gem
140
140
  # (By default this auto-creates models, controllers, views, and routes on-the-fly.)
141
141
 
142
- if Object.const_defined?('Brick')
142
+ if ActiveRecord::Base.respond_to?(:brick_select)
143
143
  # Mode -- generally :on or :off, or only in :development. Also available is :diag_env which enables only
144
144
  # when the environment variable BRICK is set.
145
145
  Brick.mode = :development
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.89
4
+ version: 1.0.91
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-11-03 00:00:00.000000000 Z
11
+ date: 2022-11-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord