brick 1.0.130 → 1.0.132

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: 902948e0d502bc9c1b604f3e99b975ab8c7d42c378888280d84dac6aef2aa7d0
4
- data.tar.gz: 82988754dcae3ccc67eb5997531b3fa218ecf364f076ecf221fac201412baff0
3
+ metadata.gz: '08cc0b19ab0838b667534f4de64f3a7045bf395202a3602981a20ececdc91ab5'
4
+ data.tar.gz: 4b976489a05bb26c3702746700025c6bad3bb930fc129ae897bc9e1596a50901
5
5
  SHA512:
6
- metadata.gz: 780184ebc02c020389bc2239e115e885df056fa6895ed32bd35b5315f2e55f86deb679f2966e7290118bc54f4d50478b4240d7d77470d27a5902af22948d83f1
7
- data.tar.gz: 39c37a9db2c7c392209491e1609f8ab4c2b64d27371452b60310d326bd462b5e653196697d0faf8f4bf801793400e073bf73f2ed72a38e9c66bd9b8e98d1e778
6
+ metadata.gz: 580db611d4ab9e2bf7ab0ed62a90940b90a4818619a9a91788802f017845c0aef3c8da1b01ea8a6a87c8e1af8378dc5c0d030396ebebba05d101b46ca0bd4495
7
+ data.tar.gz: fe876de91852b7213fa4d35b378935c7f18e18ae09ff5058f0d34b32dcb3c802a15d1c2cc79f63f7b5eac4177b7bbbeae43603e55499447cfee9e1d3556f64fa
@@ -670,6 +670,7 @@ module ActiveRecord
670
670
  link_back = []
671
671
  # Track polymorphic type field if necessary
672
672
  if hm.source_reflection.options[:as]
673
+ # Might be able to simplify as: hm.source_reflection.type
673
674
  poly_ft = [hm.source_reflection.inverse_of.foreign_type, hmt_assoc.source_reflection.class_name]
674
675
  end
675
676
  # link_back << hm.source_reflection.inverse_of.name
@@ -753,7 +754,8 @@ module ActiveRecord
753
754
 
754
755
  pri_tbl = hm.active_record
755
756
  pri_key = hm.options[:primary_key] || pri_tbl.primary_key
756
- unless hm.klass.column_names.include?(pri_key)
757
+ unless hm.active_record.column_names.include?(pri_key)
758
+ # %%% When this gets hit then if an attempt is made to display the ERD, it might end up being blank
757
759
  nix << k
758
760
  next
759
761
  end
@@ -874,6 +876,12 @@ JOIN (SELECT #{hm_selects.map { |s| "#{'br_t0.' if from_clause}#{s}" }.join(', '
874
876
  def brick_list
875
877
  pks = klass.primary_key.is_a?(String) ? [klass.primary_key] : klass.primary_key
876
878
  selects = pks.each_with_object([]) { |pk, s| s << pk unless s.include?(pk) }
879
+ # Get foreign keys for anything marked to be auto-preloaded, or a self-referencing JOIN
880
+ klass_cols = klass.column_names
881
+ reflect_on_all_associations.each do |a|
882
+ selects << a.foreign_key if a.belongs_to? && (preload_values.include?(a.name) ||
883
+ (!a.options[:polymorphic] && a.klass == klass && klass_cols.include?(a.foreign_key)))
884
+ end
877
885
  # ActiveStorage compatibility
878
886
  selects << 'service_name' if klass.name == 'ActiveStorage::Blob' && ActiveStorage::Blob.columns_hash.key?('service_name')
879
887
  selects << 'blob_id' if klass.name == 'ActiveStorage::Attachment' && ActiveStorage::Attachment.columns_hash.key?('blob_id')
@@ -1013,16 +1021,17 @@ Module.class_exec do
1013
1021
  is_controller = requested.end_with?('Controller')
1014
1022
  # self.name is nil when a model name is requested in an .erb file
1015
1023
  if self.name && ::Brick.config.path_prefix
1016
- camelize_prefix = ::Brick.config.path_prefix.camelize
1024
+ split_self_name.shift if (split_self_name = self.name.split('::')).first.blank?
1017
1025
  # Asking for the prefix module?
1026
+ camelize_prefix = ::Brick.config.path_prefix.camelize
1018
1027
  if self == Object && requested == camelize_prefix
1019
1028
  Object.const_set(args.first, (built_module = Module.new))
1020
1029
  puts "module #{camelize_prefix}; end\n"
1021
1030
  return built_module
1022
- end
1023
- split_self_name.shift if (split_self_name = self.name.split('::')).first.blank?
1024
- if split_self_name.first == camelize_prefix
1031
+ elsif module_parent == Object && self.name == camelize_prefix ||
1032
+ module_parent.name == camelize_prefix && module_parent.module_parent == Object
1025
1033
  split_self_name.shift # Remove the identified path prefix from the split name
1034
+ is_brick_prefix = true
1026
1035
  if is_controller
1027
1036
  brick_root = split_self_name.empty? ? self : camelize_prefix.constantize
1028
1037
  end
@@ -1055,26 +1064,30 @@ Module.class_exec do
1055
1064
  self
1056
1065
  end
1057
1066
  # puts "#{self.name} - #{args.first}"
1058
- desired_classname = (self == Object || !name) ? requested : "#{name}::#{requested}"
1059
- if ((is_defined = self.const_defined?(args.first)) && (possible = self.const_get(args.first)) &&
1060
- # Reset `possible` if it's a controller request that's not a perfect match
1061
- # Was: (possible = nil) but changed to #local_variable_set in order to suppress the "= should be ==" warning
1062
- (possible&.name == desired_classname || (is_controller && binding.local_variable_set(:possible, nil)))) ||
1063
- # Try to require the respective Ruby file
1064
- ((filename = ActiveSupport::Dependencies.search_for_file(desired_classname.underscore) ||
1065
- (self != Object && ActiveSupport::Dependencies.search_for_file((desired_classname = requested).underscore))
1066
- ) && (require_dependency(filename) || true) &&
1067
- ((possible = self.const_get(args.first)) && possible.name == desired_classname)
1068
- ) ||
1069
- # If any class has turned up so far (and we're not in the middle of eager loading)
1070
- # then return what we've found.
1071
- (is_defined && !::Brick.is_eager_loading) # Used to also have: && possible != self
1072
- if ((!brick_root && (filename || possible.instance_of?(Class))) ||
1073
- (possible.instance_of?(Module) && possible&.module_parent == self) ||
1074
- (possible.instance_of?(Class) && possible == self)) && # Are we simply searching for ourselves?
1075
- # Skip when what we found as `possible` is not related to the base class of an STI model
1076
- (!sti_base || possible.is_a?(sti_base))
1077
- return possible
1067
+ # Unless it's a Brick prefix looking for a TNP that should create a module ...
1068
+ unless (is_tnp_module = (is_brick_prefix && !is_controller && ::Brick.config.table_name_prefixes.values.include?(requested)))
1069
+ # ... first look around for an existing module or class.
1070
+ desired_classname = (self == Object || !name) ? requested : "#{name}::#{requested}"
1071
+ if ((is_defined = self.const_defined?(args.first)) && (possible = self.const_get(args.first)) &&
1072
+ # Reset `possible` if it's a controller request that's not a perfect match
1073
+ # Was: (possible = nil) but changed to #local_variable_set in order to suppress the "= should be ==" warning
1074
+ (possible&.name == desired_classname || (is_controller && binding.local_variable_set(:possible, nil)))) ||
1075
+ # Try to require the respective Ruby file
1076
+ ((filename = ActiveSupport::Dependencies.search_for_file(desired_classname.underscore) ||
1077
+ (self != Object && ActiveSupport::Dependencies.search_for_file((desired_classname = requested).underscore))
1078
+ ) && (require_dependency(filename) || true) &&
1079
+ ((possible = self.const_get(args.first)) && possible.name == desired_classname)
1080
+ ) ||
1081
+ # If any class has turned up so far (and we're not in the middle of eager loading)
1082
+ # then return what we've found.
1083
+ (is_defined && !::Brick.is_eager_loading) # Used to also have: && possible != self
1084
+ if ((!brick_root && (filename || possible.instance_of?(Class))) ||
1085
+ (possible.instance_of?(Module) && possible&.module_parent == self) ||
1086
+ (possible.instance_of?(Class) && possible == self)) && # Are we simply searching for ourselves?
1087
+ # Skip when what we found as `possible` is not related to the base class of an STI model
1088
+ (!sti_base || possible.is_a?(sti_base))
1089
+ return possible
1090
+ end
1078
1091
  end
1079
1092
  end
1080
1093
  class_name = ::Brick.namify(requested)
@@ -1109,7 +1122,7 @@ Module.class_exec do
1109
1122
  (plural_class_name = class_name.pluralize)].find { |s| Brick.db_schemas&.include?(s) }&.camelize ||
1110
1123
  (::Brick.config.sti_namespace_prefixes&.key?("::#{class_name}::") && class_name) ||
1111
1124
  (::Brick.config.table_name_prefixes.values.include?(class_name) && class_name))
1112
- return self.const_get(schema_name) if self.const_defined?(schema_name)
1125
+ return self.const_get(schema_name) if !is_tnp_module && self.const_defined?(schema_name)
1113
1126
 
1114
1127
  # Build out a module for the schema if it's namespaced
1115
1128
  # schema_name = schema_name.camelize
@@ -3,7 +3,7 @@
3
3
  module Brick
4
4
  module Rails
5
5
  class << self
6
- def display_value(col_type, val)
6
+ def display_value(col_type, val, lat_lng = nil)
7
7
  is_mssql_geography = nil
8
8
  # Some binary thing that really looks like a Microsoft-encoded WGS84 point? (With the first two bytes, E6 10, indicating an EPSG code of 4326)
9
9
  if col_type == :binary && val && val.length < 31 && (val.length - 6) % 8 == 0 && val[0..5].bytes == [230, 16, 0, 0, 1, 12]
@@ -61,14 +61,19 @@ module Brick
61
61
  ::Brick::Rails.display_binary(val)
62
62
  else
63
63
  if col_type
64
- ::Brick::Rails::FormBuilder.hide_bcrypt(val, col_type == :xml)
64
+ if lat_lng
65
+ # Create a link to this style of Google maps URL: https://www.google.com/maps/place/38.7071296+-121.2810649/@38.7071296,-121.2810649,12z
66
+ "<a href=\"https://www.google.com/maps/place/#{lat_lng.first}+#{lat_lng.last}/@#{lat_lng.first},#{lat_lng.last},12z\" target=\"blank\">#{val}</a>"
67
+ else
68
+ ::Brick::Rails::FormBuilder.hide_bcrypt(val, col_type == :xml)
69
+ end
65
70
  else
66
71
  '?'
67
72
  end
68
73
  end
69
74
  end
70
75
 
71
- def display_binary(val)
76
+ def display_binary(val, max_size = 100_000)
72
77
  return unless val
73
78
 
74
79
  @image_signatures ||= { (+"\xFF\xD8\xFF\xEE").force_encoding('ASCII-8BIT') => 'jpeg',
@@ -94,15 +99,12 @@ module Brick
94
99
  val = val[object_start...object_start + real_object_size]
95
100
  end
96
101
 
97
- if (signature = @image_signatures.find { |k, _v| val[0...k.length] == k }) ||
98
- (val[0..3] == 'RIFF' && val[8..11] == 'WEBP' && (signature = 'webp'))
99
- if val.length < 500_000
100
- "<img src=\"data:image/#{signature.last};base64,#{Base64.encode64(val)}\">"
101
- else
102
- "&lt;&nbsp;#{signature.last} image, #{val.length} bytes&nbsp;>"
103
- end
102
+ if ((signature = @image_signatures.find { |k, _v| val[0...k.length] == k }&.last) ||
103
+ (val[0..3] == 'RIFF' && val[8..11] == 'WEBP' && binding.local_variable_set(:signature, 'webp'))) &&
104
+ val.length < max_size
105
+ "<img src=\"data:image/#{signature.last};base64,#{Base64.encode64(val)}\">"
104
106
  else
105
- "&lt;&nbsp;Binary, #{val.length} bytes&nbsp;>"
107
+ "&lt;&nbsp;#{signature ? "#{signature} image" : 'Binary'}, #{val.length} bytes&nbsp;>"
106
108
  end
107
109
  end
108
110
  end
@@ -225,7 +227,7 @@ function linkSchemas() {
225
227
  end
226
228
 
227
229
  # When table names have specific prefixes, automatically place them in their own module with a table_name_prefix.
228
- ::Brick.table_name_prefixes = app.config.brick.fetch(:table_name_prefixes, {})
230
+ ::Brick.config.table_name_prefixes ||= app.config.brick.fetch(:table_name_prefixes, {})
229
231
 
230
232
  # Columns to treat as being metadata for purposes of identifying associative tables for has_many :through
231
233
  ::Brick.metadata_columns = app.config.brick.fetch(:metadata_columns, ['created_at', 'updated_at', 'deleted_at'])
@@ -625,6 +627,7 @@ window.addEventListener(\"popstate\", linkSchemas);
625
627
  if (class_name = (resource_parts = resource_name.split('/')).last&.singularize)
626
628
  resource_parts[-1] = class_name # Make sure the last part, defining the class name, is singular
627
629
  begin
630
+ resource_parts.shift if resource_parts.first == ::Brick.config.path_prefix
628
631
  if (model = Object.const_get(resource_parts.map(&:camelize).join('::')))&.is_a?(Class) && (
629
632
  ['index', 'show'].include?(find_args.first) || # Everything has index and show
630
633
  # Only CUD stuff has create / update / destroy
@@ -1635,10 +1638,10 @@ end
1635
1638
  <tr><td colspan=\"2\">(No displayable fields)</td></tr>
1636
1639
  <% end %>
1637
1640
  </table>#{
1638
- "<%= binary = begin
1639
- ::Brick::Rails.display_binary(obj&.blob&.download)&.html_safe
1640
- rescue
1641
- end %>" if model_name == 'ActiveStorage::Attachment'}
1641
+ "<%= begin
1642
+ ::Brick::Rails.display_binary(obj&.blob&.download, 500_000)&.html_safe
1643
+ rescue
1644
+ end %>" if model_name == 'ActiveStorage::Attachment'}
1642
1645
  <% end %>
1643
1646
 
1644
1647
  #{unless args.first == 'new'
@@ -1669,11 +1672,11 @@ end
1669
1672
  <% if (assoc = @#{obj_name}.class.reflect_on_association(:#{hm_name})).macro == :has_one &&
1670
1673
  assoc.options&.fetch(:through, nil).nil?
1671
1674
  # In order to apply DSL properly, evaluate this HO the other way around as if it were as a BT
1672
- collection = assoc.klass.where(assoc.foreign_key => @#{obj_name}.#{pk})
1675
+ collection = assoc.klass.where(assoc.foreign_key => #{pk.is_a?(String) ? "@#{obj_name}.#{pk}" : pk.map { |pk_part| "@#{obj_name}.#{pk_part}" }.inspect})
1673
1676
  collection = collection.instance_exec(&assoc.scopes.first) if assoc.scopes.present?
1674
1677
  if assoc.klass.name == 'ActiveStorage::Attachment'
1675
1678
  br_descrip = begin
1676
- ::Brick::Rails.display_binary(obj.send(assoc.name)&.blob&.download)&.html_safe
1679
+ ::Brick::Rails.display_binary(obj.send(assoc.name)&.blob&.download, 500_000)&.html_safe
1677
1680
  rescue
1678
1681
  end
1679
1682
  end
@@ -139,8 +139,19 @@ module Brick::Rails::FormTags
139
139
  out << if @_brick_monetized_attributes&.include?(col_name)
140
140
  val ? Money.new(val.to_i).format : ''
141
141
  else
142
+ lat_lng = if [:float, :decimal].include?(col.type) &&
143
+ (
144
+ ((col_name == 'latitude' && obj.respond_to?('longitude') && (lng = obj.send('longitude')) && lng.is_a?(Numeric) && (lat = val)) ||
145
+ (col_name == 'longitude' && obj.respond_to?('latitude') && (lat = obj.send('latitude')) && lat.is_a?(Numeric) && (lng = val))
146
+ ) ||
147
+ ((col_name == 'lat' && obj.respond_to?('lng') && (lng = obj.send('lng')) && lng.is_a?(Numeric) && (lat = val)) ||
148
+ (col_name == 'lng' && obj.respond_to?('lat') && (lat = obj.send('lat')) && lat.is_a?(Numeric) && (lng = val))
149
+ )
150
+ )
151
+ [lat, lng]
152
+ end
142
153
  col_type = col&.sql_type == 'geography' ? col.sql_type : col&.type
143
- ::Brick::Rails.display_value(col_type || col&.sql_type, val).to_s
154
+ ::Brick::Rails.display_value(col_type || col&.sql_type, val, lat_lng).to_s
144
155
  end
145
156
  elsif cust_col
146
157
  data = cust_col.first.map { |cc_part| obj.send(cc_part.last) }
@@ -5,7 +5,7 @@ module Brick
5
5
  module VERSION
6
6
  MAJOR = 1
7
7
  MINOR = 0
8
- TINY = 130
8
+ TINY = 132
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
@@ -125,6 +125,7 @@ if Gem::Specification.all_names.any? { |g| g.start_with?('rails-') }
125
125
  end
126
126
  module Brick
127
127
  ALL_API_ACTIONS = [:index, :show, :create, :update, :destroy]
128
+ CURRENCY_SYMBOLS = '$£¢₵€₠ƒ¥₿₩₪₹₫₴₱₲₳₸₺₼₽៛₡₢₣₤₥₦₧₨₭₮₯₰₶₷₻₾'
128
129
 
129
130
  class << self
130
131
  def sti_models
@@ -200,9 +201,20 @@ module Brick
200
201
  end
201
202
 
202
203
  def get_bts_and_hms(model)
204
+ model_cols = model.columns_hash
205
+ pk_type = if (mpk = model.primary_key).is_a?(Array)
206
+ # Composite keys should really use: model.primary_key.map { |pk_part| model_cols[pk_part].type }
207
+ model_cols[mpk.first].type
208
+ else
209
+ mpk && model_cols[mpk].type
210
+ end
203
211
  bts, hms = model.reflect_on_all_associations.each_with_object([{}, {}]) do |a, s|
212
+ # %%% The time will come when we will support type checking of composite foreign keys!
213
+ # binding.pry if a.foreign_key.is_a?(Array)
204
214
  next unless a.polymorphic? || (!a.belongs_to? && (through = a.options[:through])) ||
205
- (a.klass && ::Brick.config.exclude_tables.exclude?(a.klass.table_name))
215
+ (a.klass && ::Brick.config.exclude_tables.exclude?(a.klass.table_name) &&
216
+ (!a.belongs_to? || model_cols[a.foreign_key]&.type == pk_type)
217
+ )
206
218
 
207
219
  if a.belongs_to?
208
220
  if a.polymorphic?
@@ -239,6 +251,15 @@ module Brick
239
251
  puts "WARNING: HMT relationship :#{a.name} in model #{model.name} has invalid source :#{a.source_reflection_name}."
240
252
  next
241
253
  end
254
+ else
255
+ if !a.options.key?(:as) && a.klass.column_names.exclude?(a.foreign_key)
256
+ options = ", #{a.options.map { |k, v| "#{k.inspect} => #{v.inspect}" }.join(', ')}" if a.options.present?
257
+ puts "WARNING: Model #{model.name} has this association:
258
+ has_many :#{a.name}#{options}
259
+ which expects column #{a.foreign_key} to exist in table #{a.klass.table_name}. This column is missing."
260
+ next
261
+
262
+ end
242
263
  end
243
264
  s.last[a.name] = a
244
265
  end
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.130
4
+ version: 1.0.132
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lorin Thwaits
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-04-13 00:00:00.000000000 Z
11
+ date: 2023-04-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord