activerecord-virtual_attributes 2.0.0 → 6.1.1

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.
@@ -101,242 +101,76 @@ module ActiveRecord
101
101
  module Associations
102
102
  class Preloader
103
103
  prepend(Module.new {
104
- if ActiveRecord.version.to_s >= "6.0"
105
- # preloader.rb active record 6.0
106
- # changed:
107
- # since grouped_records can return a hash/array, we need to handle those 2 new cases
108
- def preloaders_for_reflection(reflection, records, scope, polymorphic_parent)
109
- case reflection
110
- when Array
111
- reflection.flat_map { |ref| preloaders_on(ref, records, scope, polymorphic_parent) }
112
- when Hash
113
- preloaders_on(reflection, records, scope, polymorphic_parent)
114
- else
115
- super(reflection, records, scope)
116
- end
117
- end
118
- elsif ActiveRecord.version.to_s >= "5.2" # < 6.0
119
- # preloader.rb active record 6.0
120
- # else block changed to reflect how 5.2 preloaders_for_one works
121
- def preloaders_for_reflection(reflection, records, scope, polymorphic_parent)
122
- case reflection
123
- when Array
124
- reflection.flat_map { |ref| preloaders_on(ref, records, scope, polymorphic_parent) }
125
- when Hash
126
- preloaders_on(reflection, records, scope, polymorphic_parent)
127
- else
128
- records.group_by { |record| record.association(reflection.name).klass }.map do |rhs_klass, rs|
129
- loader = preloader_for(reflection, rs).new(rhs_klass, rs, reflection, scope)
130
- loader.run(self)
131
- loader
132
- end
133
- end
134
- end
135
-
136
- # preloader.rb active record 6.0
137
- # since this deals with polymorphic_parent, it makes everything easier to just define it
138
- def preloaders_on(association, records, scope, polymorphic_parent = false)
139
- case association
140
- when Hash
141
- preloaders_for_hash(association, records, scope, polymorphic_parent)
142
- when Symbol, String
143
- preloaders_for_one(association.to_sym, records, scope, polymorphic_parent)
144
- else
145
- raise ArgumentError, "#{association.inspect} was not recognized for preload"
104
+ # preloader.rb active record 6.0
105
+ # changed:
106
+ # since grouped_records can return a hash/array, we need to handle those 2 new cases
107
+ def preloaders_for_reflection(reflection, records, scope, polymorphic_parent)
108
+ case reflection
109
+ when Array
110
+ reflection.flat_map { |ref| preloaders_on(ref, records, scope, polymorphic_parent) }
111
+ when Hash
112
+ preloaders_on(reflection, records, scope, polymorphic_parent)
113
+ else
114
+ super(reflection, records, scope)
115
+ end
116
+ end
117
+
118
+ # rubocop:disable Style/BlockDelimiters, Lint/AmbiguousBlockAssociation, Style/MethodCallWithArgsParentheses
119
+ # preloader.rb active record 6.0
120
+ # changed:
121
+ # passing polymorphic around (and makes 5.2 more similar to 6.0)
122
+ def preloaders_for_hash(association, records, scope, polymorphic_parent)
123
+ association.flat_map { |parent, child|
124
+ grouped_records(parent, records, polymorphic_parent).flat_map do |reflection, reflection_records|
125
+ loaders = preloaders_for_reflection(reflection, reflection_records, scope, polymorphic_parent)
126
+ recs = loaders.flat_map(&:preloaded_records).uniq
127
+ child_polymorphic_parent = reflection && reflection.respond_to?(:options) && reflection.options[:polymorphic]
128
+ loaders.concat Array.wrap(child).flat_map { |assoc|
129
+ preloaders_on assoc, recs, scope, child_polymorphic_parent
130
+ }
131
+ loaders
146
132
  end
147
- end
133
+ }
148
134
  end
149
135
 
150
- if ActiveRecord.version.to_s >= "5.2"
151
- # rubocop:disable Style/BlockDelimiters, Lint/AmbiguousBlockAssociation, Style/MethodCallWithArgsParentheses
152
- # preloader.rb active record 6.0
153
- # changed:
154
- # passing polymorphic around (and makes 5.2 more similar to 6.0)
155
- def preloaders_for_hash(association, records, scope, polymorphic_parent)
156
- association.flat_map { |parent, child|
157
- grouped_records(parent, records, polymorphic_parent).flat_map do |reflection, reflection_records|
158
- loaders = preloaders_for_reflection(reflection, reflection_records, scope, polymorphic_parent)
159
- recs = loaders.flat_map(&:preloaded_records).uniq
160
- child_polymorphic_parent = reflection && reflection.respond_to?(:options) && reflection.options[:polymorphic]
161
- loaders.concat Array.wrap(child).flat_map { |assoc|
162
- preloaders_on assoc, recs, scope, child_polymorphic_parent
163
- }
164
- loaders
165
- end
166
- }
167
- end
168
-
169
- # preloader.rb active record 6.0
170
- # changed:
171
- # passing polymorphic_parent to preloaders_for_reflection
172
- def preloaders_for_one(association, records, scope, polymorphic_parent)
173
- grouped_records(association, records, polymorphic_parent)
174
- .flat_map do |reflection, reflection_records|
175
- preloaders_for_reflection(reflection, reflection_records, scope, polymorphic_parent)
176
- end
177
- end
178
-
179
- # preloader.rb active record 6.0
180
- # changed:
181
- # different from 5.2. But not called outside these redefined methods here, so it works fine
182
- # did add compact to fix a 5.2 double preload nil bug
183
- def grouped_records(orig_association, records, polymorphic_parent)
184
- h = {}
185
- records.compact.each do |record|
186
- # each class can resolve virtual_{attributes,includes} differently
187
- association = record.class.replace_virtual_fields(orig_association)
188
- # 1 line optimization for single element array:
189
- association = association.first if association.kind_of?(Array) && association.size == 1
190
-
191
- case association
192
- when Symbol, String
193
- # 4/24/20 we want to revert #67 once we handle all these error cases in our codebase.
194
- reflection = record.class._reflect_on_association(association)
195
- display_virtual_attribute_deprecation("#{record.class.name}.#{association} does not exist") if !reflection && !polymorphic_parent
196
- next if !reflection || !record.association(association).klass
197
- when nil
198
- next
199
- else # need parent (preloaders_for_{hash,one}) to handle this Array/Hash
200
- reflection = association
201
- end
202
- (h[reflection] ||= []) << record
203
- end
204
- h
205
- end
206
- # rubocop:enable Style/BlockDelimiters, Lint/AmbiguousBlockAssociation, Style/MethodCallWithArgsParentheses
207
-
208
- def display_virtual_attribute_deprecation(str)
209
- short_caller = caller
210
- # if debugging is turned on, don't prune the backtrace.
211
- # if debugging is off, prune down to the line where the sql is executed
212
- # this defaults to false and only displays 1 line number.
213
- unless ActiveSupport::Deprecation.debug
214
- bc = ActiveSupport::BacktraceCleaner.new
215
- bc.add_silencer { |line| line =~ /virtual_fields/ }
216
- bc.add_silencer { |line| line =~ /active_record/ }
217
- short_caller = bc.clean(caller)
136
+ # preloader.rb active record 6.0
137
+ # changed:
138
+ # passing polymorphic_parent to preloaders_for_reflection
139
+ def preloaders_for_one(association, records, scope, polymorphic_parent)
140
+ grouped_records(association, records, polymorphic_parent)
141
+ .flat_map do |reflection, reflection_records|
142
+ preloaders_for_reflection(reflection, reflection_records, scope, polymorphic_parent)
218
143
  end
144
+ end
219
145
 
220
- ActiveSupport::Deprecation.warn(str, short_caller)
221
- end
222
- else
223
- def preloaders_for_one(association, records, scope)
224
- klass_map = records.compact.group_by(&:class)
146
+ # preloader.rb active record 6.0, 6.1
147
+ def grouped_records(orig_association, records, polymorphic_parent)
148
+ h = {}
149
+ records.each do |record|
150
+ # The virtual_field lookup can return Symbol/Nil/Other (typically a Hash)
151
+ # so the case statement and the cases for Nil/Other are new
225
152
 
226
- # new logic: preload virtual fields / virtual includes
227
- loaders = klass_map.keys.group_by { |klass| klass.virtual_includes(association) }.flat_map do |virtuals, klasses|
228
- subset = klasses.flat_map { |klass| klass_map[klass] }
229
- preload(subset, virtuals)
230
- end
231
- # /new logic
153
+ # each class can resolve virtual_{attributes,includes} differently
154
+ association = record.class.replace_virtual_fields(orig_association)
155
+ # 1 line optimization for single element array:
156
+ association = association.first if association.kind_of?(Array) && association.size == 1
232
157
 
233
- records_with_association = klass_map.select { |k, _rs| k.reflect_on_association(association) }.flat_map { |_k, rs| rs }
234
- if records_with_association.any?
235
- loaders.concat(super(association, records_with_association, scope))
158
+ case association
159
+ when Symbol, String
160
+ reflection = record.class._reflect_on_association(association)
161
+ next if polymorphic_parent && !reflection || !record.association(association).klass
162
+ when nil
163
+ next
164
+ else # need parent (preloaders_for_{hash,one}) to handle this Array/Hash
165
+ reflection = association
236
166
  end
237
-
238
- loaders
167
+ (h[reflection] ||= []) << record
239
168
  end
169
+ h
240
170
  end
171
+ # rubocop:enable Style/BlockDelimiters, Lint/AmbiguousBlockAssociation, Style/MethodCallWithArgsParentheses
241
172
  })
242
173
  end
243
-
244
- # FIXME: Hopefully we can get this into Rails core so this is no longer
245
- # required in our codebase, but the rule that are broken here are mostly
246
- # due to the style of the Rails codebase conflicting with our own.
247
- # Ignoring them to avoid noise in RuboCop, but allow us to keep the same
248
- # syntax from the original codebase.
249
- #
250
- # rubocop:disable Style/BlockDelimiters, Layout/SpaceAfterComma, Style/HashSyntax
251
- # rubocop:disable Layout/AlignHash
252
- class JoinDependency
253
- def instantiate(result_set, *_, &block)
254
- primary_key = aliases.column_alias(join_root, join_root.primary_key)
255
-
256
- seen = Hash.new { |i, object_id|
257
- i[object_id] = Hash.new { |j, child_class|
258
- j[child_class] = {}
259
- }
260
- }
261
-
262
- model_cache = Hash.new { |h,klass| h[klass] = {} }
263
- parents = model_cache[join_root]
264
- column_aliases = aliases.column_aliases(join_root)
265
-
266
- # New Code
267
- column_aliases += select_values_from_references(column_aliases, result_set) if result_set.present?
268
- # End of New Code
269
-
270
- message_bus = ActiveSupport::Notifications.instrumenter
271
-
272
- payload = {
273
- record_count: result_set.length,
274
- class_name: join_root.base_klass.name
275
- }
276
-
277
- message_bus.instrument('instantiation.active_record', payload) do
278
- result_set.each { |row_hash|
279
- parent_key = primary_key ? row_hash[primary_key] : row_hash
280
- parent = parents[parent_key] ||= join_root.instantiate(row_hash, column_aliases, &block)
281
- if ActiveRecord.version.to_s < "6.0"
282
- construct(parent, join_root, row_hash, result_set, seen, model_cache, aliases)
283
- else
284
- construct(parent, join_root, row_hash, seen, model_cache)
285
- end
286
- }
287
- end
288
-
289
- parents.values
290
- end
291
- # rubocop:enable Style/BlockDelimiters, Layout/SpaceAfterComma, Style/HashSyntax
292
- # rubocop:enable Layout/AlignHash
293
-
294
- #
295
- # This monkey patches the ActiveRecord::Associations::JoinDependency to
296
- # include columns into the main record that might have been added
297
- # through a `select` clause.
298
- #
299
- # This can be seen with the following:
300
- #
301
- # Vm.select(Vm.arel_table[Arel.star]).select(:some_vm_virtual_col)
302
- # .includes(:tags => {}).references(:tags)
303
- #
304
- # Which will produce a SQL SELECT statement kind of like this:
305
- #
306
- # SELECT "vms".*,
307
- # (<virtual_attribute_arel>) AS some_vm_virtual_col,
308
- # "vms"."id" AS t0_r0
309
- # "vms"."vendor" AS t0_r1
310
- # "vms"."format" AS t0_r1
311
- # "vms"."version" AS t0_r1
312
- # ...
313
- # "tags"."id" AS t1_r0
314
- # "tags"."name" AS t1_r1
315
- #
316
- # This is because rails is trying to reduce the number of queries
317
- # needed to fetch all of the records in the include, so it grabs the
318
- # columns for both of the tables together to do it. Unfortunately (or
319
- # fortunately... depending on how you look at it), it does not remove
320
- # any `.select` columns from the query that is run in the process, so
321
- # that is brought along for the ride, but never used when this method
322
- # instanciates the objects.
323
- #
324
- # The "New Code" here simply also instanciates any extra rows that
325
- # might have been included in the select (virtual_columns) as well and
326
- # brought back with the result set.
327
- def select_values_from_references(column_aliases, result_set)
328
- join_dep_keys = aliases.columns.map(&:right)
329
- join_root_aliases = column_aliases.map(&:first)
330
- additional_attributes = result_set.first.keys
331
- .reject { |k| join_dep_keys.include?(k) }
332
- .reject { |k| join_root_aliases.include?(k) }
333
- if ActiveRecord.version.to_s >= "6.0"
334
- additional_attributes.map { |k| Aliases::Column.new(k, k) }
335
- else
336
- additional_attributes.map { |k| [k, k] }
337
- end
338
- end
339
- end
340
174
  end
341
175
 
342
176
  class Relation
@@ -351,99 +185,50 @@ module ActiveRecord
351
185
 
352
186
  include(Module.new {
353
187
  # From ActiveRecord::FinderMethods
354
- if ActiveRecord.version.to_s >= "5.2"
355
- def apply_join_dependency(*args, &block)
356
- real = without_virtual_includes
357
- if real.equal?(self)
358
- super
359
- else
360
- real.apply_join_dependency(*args, &block)
361
- end
362
- end
363
- else
364
- def find_with_associations(&block)
365
- real = without_virtual_includes
366
- if real.equal?(self)
367
- super
368
- else
369
- real.find_with_associations(&block)
370
- end
188
+ def apply_join_dependency(*args, **kargs, &block)
189
+ real = without_virtual_includes
190
+ if real.equal?(self)
191
+ super
192
+ else
193
+ real.apply_join_dependency(*args, **kargs, &block)
371
194
  end
372
195
  end
373
196
 
374
- # From ActiveRecord::QueryMethods (rails 5.2 - 6.0)
197
+ # From ActiveRecord::QueryMethods (rails 5.2 - 6.1)
375
198
  def build_select(arel)
376
199
  if select_values.any?
377
- arel.project(*arel_columns(select_values.uniq, true))
378
- elsif klass.ignored_columns.any?
379
- arel.project(*klass.column_names.map { |field| arel_attribute(field) })
380
- else
381
- arel.project(table[Arel.star])
382
- end
383
- end
384
-
385
- # from ActiveRecord::QueryMethods (rails 5.2 - 6.0)
386
- def arel_columns(columns, allow_alias = false)
387
- columns.flat_map do |field|
388
- case field
389
- when Symbol
390
- arel_column(field.to_s, allow_alias) do |attr_name|
391
- connection.quote_table_name(attr_name)
200
+ cols = arel_columns(select_values.uniq).map do |col|
201
+ # if it is a virtual attribute, then add aliases to those columns
202
+ if col.kind_of?(Arel::Nodes::Grouping) && col.name
203
+ col.as(connection.quote_column_name(col.name))
204
+ else
205
+ col
392
206
  end
393
- when String
394
- arel_column(field, allow_alias, &:itself)
395
- when Proc
396
- field.call
397
- else
398
- field
399
207
  end
400
- end
401
- end
402
-
403
- # from ActiveRecord::QueryMethods (rails 5.2 - 6.0)
404
- def arel_column(field, allow_alias = false, &block)
405
- field = klass.attribute_aliases[field] || field
406
- from = from_clause.name || from_clause.value
407
-
408
- if klass.columns_hash.key?(field) && (!from || table_name_matches?(from))
409
- arel_attribute(field)
410
- elsif virtual_attribute?(field)
411
- virtual_attribute_arel_column(field, allow_alias, &block)
208
+ arel.project(*cols)
412
209
  else
413
- yield field
210
+ super
414
211
  end
415
212
  end
416
213
 
417
- def virtual_attribute_arel_column(field, allow_alias)
418
- arel = arel_attribute(field)
419
- if arel.nil?
420
- yield field
421
- elsif allow_alias && arel && arel.respond_to?(:as) && !arel.kind_of?(Arel::Nodes::As) && !arel.try(:alias)
422
- arel.as(connection.quote_column_name(field.to_s))
423
- else
214
+ # from ActiveRecord::QueryMethods (rails 5.2 - 6.0)
215
+ # TODO: remove from rails 7.0
216
+ def arel_column(field, &block)
217
+ if virtual_attribute?(field) && (arel = table[field])
424
218
  arel
219
+ else
220
+ super
425
221
  end
426
222
  end
427
223
 
428
- # From ActiveRecord::QueryMethods
429
- def table_name_matches?(from)
430
- /(?:\A|(?<!FROM)\s)(?:\b#{table.name}\b|#{connection.quote_table_name(table.name)})(?!\.)/i.match?(from.to_s)
431
- end
432
-
433
- # From ActiveRecord::QueryMethods
434
- def build_left_outer_joins(manager, outer_joins, *rest)
435
- outer_joins = klass.replace_virtual_fields(outer_joins)
436
- super if outer_joins.present?
224
+ def construct_join_dependency(associations, join_type) # :nodoc:
225
+ associations = klass.replace_virtual_fields(associations)
226
+ super
437
227
  end
438
228
 
439
229
  # From ActiveRecord::Calculations
230
+ # introduces virtual includes support for calculate (we mostly use COUNT(*))
440
231
  def calculate(operation, attribute_name)
441
- if ActiveRecord.version.to_s < "5.1"
442
- if (arel = klass.arel_attribute(attribute_name)) && virtual_attribute?(attribute_name)
443
- attribute_name = arel
444
- end
445
- end
446
-
447
232
  # allow calculate to work with includes and a virtual attribute
448
233
  real = without_virtual_includes
449
234
  return super if real.equal?(self)
@@ -5,7 +5,7 @@ module VirtualAttributes
5
5
  module ClassMethods
6
6
  private
7
7
 
8
- # define an attribute to calculating the total of a has many relationship
8
+ # define an attribute to calculate the total of a has many relationship
9
9
  #
10
10
  # example:
11
11
  #
@@ -25,24 +25,45 @@ module VirtualAttributes
25
25
  # # arel == (SELECT COUNT(*) FROM vms where ems.id = vms.ems_id)
26
26
  #
27
27
  def virtual_total(name, relation, options = {})
28
- define_virtual_size_method(name, relation)
29
28
  define_virtual_aggregate_attribute(name, relation, :count, Arel.star, options)
29
+ define_method(name) { (has_attribute?(name) ? self[name] : send(relation).try(:size)) || 0 }
30
30
  end
31
31
 
32
- # define an attribute to calculate the sum of a has may relationship
32
+ def virtual_sum(name, relation, column, options = {})
33
+ define_virtual_aggregate_attribute(name, relation, :sum, column, options)
34
+ define_virtual_aggregate_method(name, relation, column, :sum)
35
+ end
36
+
37
+ def virtual_minimum(name, relation, column, options = {})
38
+ define_virtual_aggregate_attribute(name, relation, :minimum, column, options)
39
+ define_virtual_aggregate_method(name, relation, column, :min, :minimum)
40
+ end
41
+
42
+ def virtual_maximum(name, relation, column, options = {})
43
+ define_virtual_aggregate_attribute(name, relation, :maximum, column, options)
44
+ define_virtual_aggregate_method(name, relation, column, :max, :maximum)
45
+ end
46
+
47
+ def virtual_average(name, relation, column, options = {})
48
+ define_virtual_aggregate_attribute(name, relation, :average, column, options)
49
+ define_virtual_aggregate_method(name, relation, column, :average) { |values| values.count == 0 ? 0 : values.sum / values.count }
50
+ end
51
+
52
+ # @param method_name
53
+ # :count :average :minimum :maximum :sum
33
54
  #
34
55
  # example:
35
56
  #
36
57
  # class Hardware
37
58
  # has_many :disks
38
- # virtual_aggregate :allocated_disk_storage, :disks, :sum, :size
59
+ # virtual_sum :allocated_disk_storage, :disks, :size
39
60
  # end
40
61
  #
41
62
  # generates:
42
63
  #
43
64
  # def allocated_disk_storage
44
65
  # if disks.loaded?
45
- # disks.blank? ? nil : disks.map(&:size).compact.sum
66
+ # disks.map(&:size).compact.sum
46
67
  # else
47
68
  # disks.sum(:size) || 0
48
69
  # end
@@ -53,10 +74,8 @@ module VirtualAttributes
53
74
  # # arel => (SELECT sum("disks"."size") where "hardware"."id" = "disks"."hardware_id")
54
75
 
55
76
  def virtual_aggregate(name, relation, method_name = :sum, column = nil, options = {})
56
- return define_virtual_total(name, relation, options) if method_name == :size
57
-
58
- define_virtual_aggregate_method(name, relation, method_name, column)
59
- define_virtual_aggregate_attribute(name, relation, method_name, column, options)
77
+ return virtual_total(name, relation, options) if method_name == :size
78
+ return virtual_sum(name, relation, column, options) if method_name == :sum
60
79
  end
61
80
 
62
81
  def define_virtual_aggregate_attribute(name, relation, method_name, column, options)
@@ -77,20 +96,19 @@ module VirtualAttributes
77
96
  end
78
97
  end
79
98
 
80
- def define_virtual_size_method(name, relation)
81
- define_method(name) do
82
- (has_attribute?(name) ? self[name] : send(relation).try(:size)) || 0
83
- end
84
- end
85
-
86
- def define_virtual_aggregate_method(name, relation, method_name, column)
99
+ def define_virtual_aggregate_method(name, relation, column, ruby_method_name, arel_method_name = ruby_method_name)
87
100
  define_method(name) do
88
- if attribute_present?(name)
89
- self[name]
101
+ if has_attribute?(name)
102
+ self[name] || 0
90
103
  elsif (rel = send(relation)).loaded?
91
- rel.blank? ? nil : rel.map { |t| t.send(column) }.compact.send(method_name)
104
+ values = rel.map { |t| t.send(column) }.compact
105
+ if block_given?
106
+ yield values
107
+ else
108
+ values.blank? ? nil : values.send(ruby_method_name)
109
+ end
92
110
  else
93
- rel.try(method_name, column) || 0
111
+ rel.try(arel_method_name, column) || 0
94
112
  end
95
113
  end
96
114
  end
@@ -101,7 +119,7 @@ module VirtualAttributes
101
119
  # need db access for the reflection join_keys, so delaying all this key lookup until call time
102
120
  lambda do |t|
103
121
  # strings and symbols are converted across, arel objects are not
104
- column = reflection.klass.arel_attribute(column) unless column.respond_to?(:count)
122
+ column = reflection.klass.arel_table[column] unless column.respond_to?(:count)
105
123
 
106
124
  # query: SELECT COUNT(*) FROM main_table JOIN foreign_table ON main_table.id = foreign_table.id JOIN ...
107
125
  relation_query = joins(reflection.name).select(column.send(method_name))
@@ -121,18 +139,16 @@ module VirtualAttributes
121
139
 
122
140
  # convert bind variables from ? to actual values. otherwise, sql is incomplete
123
141
  conn = connection
124
- sql = if ActiveRecord.version.to_s >= "5.2"
125
- conn.unprepared_statement { conn.to_sql(query) }
126
- else
127
- conn.unprepared_statement { conn.to_sql(query, relation_query.bound_attributes) }
128
- end
142
+ sql = conn.unprepared_statement { conn.to_sql(query) }
129
143
 
130
144
  # add () around query
131
- t.grouping(Arel::Nodes::SqlLiteral.new(sql))
145
+ query = t.grouping(Arel::Nodes::SqlLiteral.new(sql))
146
+ # add coalesce to ensure correct value comes out
147
+ t.grouping(Arel::Nodes::NamedFunction.new('COALESCE', [query, Arel::Nodes::SqlLiteral.new("0")]))
132
148
  end
133
149
  end
134
150
  end
135
151
  end
136
152
  end
137
153
 
138
- ActiveRecord::Base.send(:include, VirtualAttributes::VirtualTotal)
154
+ ActiveRecord::Base.include VirtualAttributes::VirtualTotal
@@ -86,14 +86,7 @@ module ActiveRecord
86
86
  def attributes_builder # :nodoc:
87
87
  unless defined?(@attributes_builder) && @attributes_builder
88
88
  defaults = _default_attributes.except(*(column_names - [primary_key]))
89
- # change necessary for rails 5.0 and 5.1 - (changed/introduced in https://github.com/rails/rails/pull/31894)
90
- defaults = defaults.except(*virtual_attribute_names)
91
- # end change
92
- @attributes_builder = if ActiveRecord.version.to_s >= "5.2"
93
- ActiveModel::AttributeSet::Builder.new(attribute_types, defaults)
94
- else
95
- ActiveRecord::AttributeSet::Builder.new(attribute_types, defaults)
96
- end
89
+ @attributes_builder = ActiveModel::AttributeSet::Builder.new(attribute_types, defaults)
97
90
  end
98
91
  @attributes_builder
99
92
  end
@@ -130,22 +123,7 @@ require "active_record/virtual_attributes/virtual_fields"
130
123
  # Class extensions
131
124
  #
132
125
 
133
- # this patch is no longer necessary for 5.2
134
- if ActiveRecord.version.to_s < "5.2"
135
- require "active_record/attribute"
136
- module ActiveRecord
137
- # This is a bug in rails 5.0 and 5.1, but it is made much worse by virtual attributes
138
- class Attribute
139
- def with_value_from_database(value)
140
- # self.class.from_database(name, value, type)
141
- initialized? ? self.class.from_database(name, value, type) : self
142
- end
143
- end
144
- end
145
- end
146
-
147
126
  require "active_record/virtual_attributes/virtual_total"
148
- require "active_record/virtual_attributes/arel_groups"
149
127
 
150
128
  # legacy support for sql types
151
129
  module VirtualAttributes