brick 1.0.88 → 1.0.90

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9e346878b216d9e54ee0ca15be13ec0c2348f8cdf81d14a1eb4bc24ccb07aadb
4
- data.tar.gz: 92b54e7227fad318508104690158b5c756cc37171e7eeaaaba41d7da97c5518f
3
+ metadata.gz: eca72d418715811a100a44a45b3cd054ca511ed280f1d1a6f344ddaa972c220c
4
+ data.tar.gz: d712ebb5dedf75da99d8d8720f4b89e29ea2e96b498b4a59540811f5e087231c
5
5
  SHA512:
6
- metadata.gz: a8797a5e8924e3a89fd958f05d1bd442cf457428257cd697e438e1e6fe93427bc035177cea79fad47c6484427b30d2e3dc778f7a2166bc0fe27d383ce8659c1c
7
- data.tar.gz: 0bd6d3cc1ad92a1ec897b1524fde2e3f6849c783705312908d206460f9060677c93c295f3f3b89ddd514e2b3d5faeae4900472b0f4a1419e57e91046a190b3f7
6
+ metadata.gz: 1b3d3941f4905b7a3ce1489a6f018d958331bd4c2970a5ba5034eb0fb81683febdc8a93562be5a1505afe6d6479fb1ed068a0f21d6ea80f24460e9e9267b8ea3
7
+ data.tar.gz: c3f61b68cd2ca5790f93b82010909f65913ccecb46df24786c83db362241092824db66833b72f03708560f23b7e87f64f12b180d8e4fb9ababba32bdb9b3f9df
@@ -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?
@@ -382,6 +383,23 @@ module ActiveRecord
382
383
  end
383
384
  end
384
385
 
386
+ module AttributeMethods
387
+ module ClassMethods
388
+ alias _brick_dangerous_attribute_method? dangerous_attribute_method?
389
+ # Bypass the error "ActiveRecord::DangerousAttributeError" if this object comes from a view.
390
+ # (Allows for column names such as 'attribute', 'delete', and 'update' to still work.)
391
+ def dangerous_attribute_method?(name)
392
+ if (is_dangerous = _brick_dangerous_attribute_method?(name)) && is_view?
393
+ if column_names.include?(name.to_s)
394
+ puts "WARNING: Column \"#{name}\" in view #{table_name} conflicts with a reserved ActiveRecord method name."
395
+ end
396
+ return false
397
+ end
398
+ is_dangerous
399
+ end
400
+ end
401
+ end
402
+
385
403
  class Relation
386
404
  attr_reader :_brick_chains, :_arel_applied_aliases
387
405
 
@@ -1058,7 +1076,7 @@ Module.class_exec do
1058
1076
  # elsif base_module != Object
1059
1077
  # module_parent.const_missing(*args)
1060
1078
  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)
1079
+ (Rails::Autoloaders.respond_to?(:zeitwerk_enabled?) ? Rails::Autoloaders.zeitwerk_enabled? : true)
1062
1080
  self._brick_const_missing(*args) # ... rely solely on Zeitwerk.
1063
1081
  else # Classic mode
1064
1082
  unless (found = base_module._brick_const_missing(*args))
@@ -1268,7 +1286,7 @@ class Object
1268
1286
  # hm.first[:inverse][:assoc_name].to_sym
1269
1287
  options[:source] = hm.last.to_sym
1270
1288
  else
1271
- through = hm.first[:alternate_name].pluralize
1289
+ through = hm.first.fetch(:alternate_chosen_name, hm.first[:alternate_name])
1272
1290
  end
1273
1291
  singular_assoc_name = hm.first[:inverse][:assoc_name].singularize
1274
1292
  "#{singular_assoc_name}_#{hmt_fk}"
@@ -1689,12 +1707,13 @@ class Object
1689
1707
  hm_assoc[:alternate_name] != (source || name.underscore)
1690
1708
  plural = "#{hm_assoc[:assoc_name]}_#{ActiveSupport::Inflector.pluralize(hm_assoc[:alternate_name])}"
1691
1709
  new_alt_name = (hm_assoc[:alternate_name] == name.underscore) ? "#{hm_assoc[:assoc_name].singularize}_#{plural}" : plural
1710
+ # %%% In rare cases might even need to add a number at the end for uniqueness
1692
1711
  # uniq = 1
1693
1712
  # while same_name = relation[:fks].find { |x| x.last[:assoc_name] == hm_assoc[:assoc_name] && x.last != hm_assoc }
1694
1713
  # hm_assoc[:assoc_name] = "#{hm_assoc_name}_#{uniq += 1}"
1695
1714
  # end
1696
1715
  # puts new_alt_name
1697
- # hm_assoc[:assoc_name] = new_alt_name
1716
+ hm_assoc[:alternate_chosen_name] = new_alt_name
1698
1717
  [new_alt_name, true]
1699
1718
  else
1700
1719
  assoc_name = ::Brick.namify(hm_assoc[:inverse_table]).pluralize
@@ -818,7 +818,16 @@ erDiagram
818
818
  end # DutyFree data export and import
819
819
  # %%% Instead of our current "for Janet Leverling (Employee)" kind of link we previously had this code that did a "where x = 123" thing:
820
820
  # (where <%= @_brick_params.each_with_object([]) { |v, s| s << \"#\{v.first\} = #\{v.last.inspect\}\" }.join(', ') %>)
821
- +"#{css}
821
+ +"<html>
822
+ <head>
823
+ #{css}
824
+ <title>#{model_name} <%
825
+ if (description = (relation = Brick.relations[#{model_name}.table_name])&.fetch(:description, nil)).present?
826
+ %> - <%= description
827
+ %><% end
828
+ %></title>
829
+ </head>
830
+ <body>
822
831
  <p style=\"color: green\"><%= notice %></p>#{"
823
832
  <select id=\"schema\">#{schema_options}</select>" if ::Brick.config.schema_behavior[:multitenant] && ::Brick.db_schemas.length > 1}
824
833
  <select id=\"tbl\">#{table_options}</select>
@@ -826,7 +835,7 @@ erDiagram
826
835
  <td><h1>#{model_name}</h1></td>
827
836
  <td id=\"imgErd\" title=\"Show ERD\"></td>
828
837
  </tr></table>#{template_link}<%
829
- if (description = (relation = Brick.relations[#{model_name}.table_name])&.fetch(:description, nil)).present? %><%=
838
+ if description.present? %><%=
830
839
  description %><br><%
831
840
  end
832
841
  # FILTER PARAMETERS
@@ -988,7 +997,10 @@ erDiagram
988
997
  </table>
989
998
 
990
999
  #{"<hr><%= link_to \"New #{obj_name}\", new_#{path_obj_name}_path %>" unless @_brick_model.is_view?}
991
- #{script}"
1000
+ #{script}
1001
+ </body>
1002
+ </html>
1003
+ "
992
1004
 
993
1005
  when 'status'
994
1006
  if is_status
@@ -1061,7 +1073,14 @@ erDiagram
1061
1073
  end
1062
1074
 
1063
1075
  when 'show', 'new', 'update'
1064
- +"#{css}
1076
+ +"<html>
1077
+ <head>
1078
+ #{css}
1079
+ <title><%=
1080
+ page_title = (\"#{model_name}: #\{(obj = @#{obj_name})&.brick_descrip || controller_name}\")
1081
+ %></title>
1082
+ </head>
1083
+ <body>
1065
1084
 
1066
1085
  <svg id=\"revertTemplate\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"
1067
1086
  width=\"32px\" height=\"32px\" viewBox=\"0 0 512 512\" xml:space=\"preserve\">
@@ -1072,7 +1091,7 @@ erDiagram
1072
1091
  <p style=\"color: green\"><%= notice %></p>#{"
1073
1092
  <select id=\"schema\">#{schema_options}</select>" if ::Brick.config.schema_behavior[:multitenant] && ::Brick.db_schemas.length > 1}
1074
1093
  <select id=\"tbl\">#{table_options}</select>
1075
- <h1>#{model_name}: <%= (obj = @#{obj_name})&.brick_descrip || controller_name %></h1><%
1094
+ <h1><%= page_title %></h1><%
1076
1095
  if (description = (relation = Brick.relations[#{model_name}.table_name])&.fetch(:description, nil)) %><%=
1077
1096
  description %><br><%
1078
1097
  end
@@ -1201,7 +1220,8 @@ end
1201
1220
  <% end %>
1202
1221
 
1203
1222
  #{unless args.first == 'new'
1204
- confirm_are_you_sure = ActionView.version < ::Gem::Version.new('7.0') ? "data: { confirm: 'Delete #{model_name} -- Are you sure?' }" : "form: { data: { turbo_confirm: 'Delete #{model_name} -- Are you sure?' } }"
1223
+ # Was: confirm_are_you_sure = ActionView.version < ::Gem::Version.new('7.0') ? "data: { confirm: 'Delete #{model_name} -- Are you sure?' }" : "form: { data: { turbo_confirm: 'Delete #{model_name} -- Are you sure?' } }"
1224
+ confirm_are_you_sure = "data: { confirm: 'Delete #{model_name} -- Are you sure?' }"
1205
1225
  hms_headers.each_with_object(+'') do |hm, s|
1206
1226
  # %%% Would be able to remove this when multiple foreign keys to same destination becomes bulletproof
1207
1227
  next if hm.first.options[:through] && !hm.first.through_reflection
@@ -1212,7 +1232,14 @@ end
1212
1232
  s << "<table id=\"#{hm_name}\" class=\"shadow\">
1213
1233
  <tr><th>#{hm[3]}</th></tr>
1214
1234
  <% collection = @#{obj_name}.#{hm_name}
1215
- collection = collection.is_a?(ActiveRecord::Associations::CollectionProxy) ? collection.order(#{pk.inspect}) : collection.to_a.compact
1235
+ collection = case collection
1236
+ when ActiveRecord::Associations::CollectionProxy
1237
+ collection.order(#{pk.inspect})
1238
+ when ActiveRecord::Base # Object from a has_one
1239
+ [collection]
1240
+ else # We get an array back when AR < 4.2
1241
+ collection.to_a.compact
1242
+ end
1216
1243
  if collection.empty? %>
1217
1244
  <tr><td>(none)</td></tr>
1218
1245
  <% else %>
@@ -1228,7 +1255,10 @@ end
1228
1255
  "<%= 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} }) %>"
1229
1256
  end}
1230
1257
  <% end %>
1231
- #{script}"
1258
+ #{script}
1259
+ </body>
1260
+ </html>
1261
+ "
1232
1262
 
1233
1263
  end
1234
1264
  inline << "
@@ -5,7 +5,7 @@ module Brick
5
5
  module VERSION
6
6
  MAJOR = 1
7
7
  MINOR = 0
8
- TINY = 88
8
+ TINY = 90
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,15 +186,15 @@ 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 !const_defined?(a.name.to_s.singularize.camelize) && ::Brick.config.exclude_tables.include?(a.plural_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)
196
196
  models = primary_tables&.map { |table| table.singularize.camelize.constantize }
197
- s.first[a.foreign_key] = [a.name, models, true]
197
+ s.first[a.foreign_key.to_s] = [a.name, models, true]
198
198
  else
199
199
  # This will come up when using Devise invitable when invited_by_class_name is not
200
200
  # specified because in that circumstance it adds a polymorphic :invited_by association,
@@ -203,10 +203,26 @@ module Brick
203
203
  puts " belongs_to :#{a.name}, polymorphic: true"
204
204
  end
205
205
  else
206
- s.first[a.foreign_key] = [a.name, a.klass]
206
+ s.first[a.foreign_key.to_s] = [a.name, a.klass]
207
+ end
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
207
225
  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
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) }
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.88
4
+ version: 1.0.90
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-02 00:00:00.000000000 Z
11
+ date: 2022-11-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord