activerecord 6.1.0.rc1 → 6.1.2.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +177 -20
- data/README.rdoc +1 -1
- data/lib/active_record/aggregations.rb +4 -4
- data/lib/active_record/association_relation.rb +10 -0
- data/lib/active_record/associations.rb +6 -2
- data/lib/active_record/associations/association.rb +14 -9
- data/lib/active_record/associations/association_scope.rb +7 -5
- data/lib/active_record/associations/belongs_to_association.rb +7 -3
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -2
- data/lib/active_record/associations/builder/association.rb +23 -2
- data/lib/active_record/associations/builder/belongs_to.rb +2 -2
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +2 -2
- data/lib/active_record/associations/join_dependency/join_association.rb +8 -7
- data/lib/active_record/attribute_methods.rb +13 -7
- data/lib/active_record/attribute_methods/serialization.rb +8 -2
- data/lib/active_record/attributes.rb +6 -1
- data/lib/active_record/callbacks.rb +121 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +8 -3
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +4 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +7 -1
- data/lib/active_record/connection_adapters/abstract/transaction.rb +24 -18
- data/lib/active_record/connection_adapters/abstract_adapter.rb +23 -8
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +6 -10
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +4 -1
- data/lib/active_record/connection_adapters/pool_config.rb +13 -3
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +1 -3
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -1
- data/lib/active_record/connection_handling.rb +11 -3
- data/lib/active_record/core.rb +51 -32
- data/lib/active_record/database_configurations/url_config.rb +1 -1
- data/lib/active_record/enum.rb +58 -31
- data/lib/active_record/fixtures.rb +4 -1
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/insert_all.rb +2 -0
- data/lib/active_record/internal_metadata.rb +2 -4
- data/lib/active_record/locking/optimistic.rb +14 -4
- data/lib/active_record/log_subscriber.rb +3 -2
- data/lib/active_record/migration/compatibility.rb +2 -1
- data/lib/active_record/model_schema.rb +29 -0
- data/lib/active_record/railtie.rb +2 -2
- data/lib/active_record/railties/console_sandbox.rb +2 -4
- data/lib/active_record/railties/databases.rake +29 -7
- data/lib/active_record/reflection.rb +2 -1
- data/lib/active_record/relation/predicate_builder.rb +6 -9
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +3 -4
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +9 -5
- data/lib/active_record/relation/query_methods.rb +9 -6
- data/lib/active_record/relation/spawn_methods.rb +2 -2
- data/lib/active_record/schema_migration.rb +2 -4
- data/lib/active_record/signed_id.rb +1 -1
- data/lib/active_record/table_metadata.rb +10 -3
- data/lib/active_record/tasks/database_tasks.rb +1 -0
- data/lib/active_record/transactions.rb +4 -2
- metadata +12 -12
@@ -751,6 +751,11 @@ module ActiveRecord
|
|
751
751
|
wait_timeout = 2147483 unless wait_timeout.is_a?(Integer)
|
752
752
|
variables["wait_timeout"] = wait_timeout
|
753
753
|
|
754
|
+
# Set the collation of the connection character set.
|
755
|
+
if @config[:collation]
|
756
|
+
variables["collation_connection"] = @config[:collation]
|
757
|
+
end
|
758
|
+
|
754
759
|
defaults = [":default", :default].to_set
|
755
760
|
|
756
761
|
# Make MySQL reject illegal values rather than truncating or blanking them, see
|
@@ -770,15 +775,6 @@ module ActiveRecord
|
|
770
775
|
end
|
771
776
|
sql_mode_assignment = "@@SESSION.sql_mode = #{sql_mode}, " if sql_mode
|
772
777
|
|
773
|
-
# NAMES does not have an equals sign, see
|
774
|
-
# https://dev.mysql.com/doc/refman/en/set-names.html
|
775
|
-
# (trailing comma because variable_assignments will always have content)
|
776
|
-
if @config[:encoding]
|
777
|
-
encoding = +"NAMES #{@config[:encoding]}"
|
778
|
-
encoding << " COLLATE #{@config[:collation]}" if @config[:collation]
|
779
|
-
encoding << ", "
|
780
|
-
end
|
781
|
-
|
782
778
|
# Gather up all of the SET variables...
|
783
779
|
variable_assignments = variables.map do |k, v|
|
784
780
|
if defaults.include?(v)
|
@@ -790,7 +786,7 @@ module ActiveRecord
|
|
790
786
|
end.compact.join(", ")
|
791
787
|
|
792
788
|
# ...and send them all in one query
|
793
|
-
execute("SET #{
|
789
|
+
execute("SET #{sql_mode_assignment} #{variable_assignments}", "SCHEMA")
|
794
790
|
end
|
795
791
|
|
796
792
|
def column_definitions(table_name) # :nodoc:
|
@@ -45,10 +45,9 @@ module ActiveRecord
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def add_table_options!(create_sql, o)
|
48
|
-
create_sql = super
|
49
48
|
create_sql << " DEFAULT CHARSET=#{o.charset}" if o.charset
|
50
49
|
create_sql << " COLLATE=#{o.collation}" if o.collation
|
51
|
-
add_sql_comment!(
|
50
|
+
add_sql_comment!(super, o.comment)
|
52
51
|
end
|
53
52
|
|
54
53
|
def add_column_options!(sql, options)
|
@@ -79,7 +79,10 @@ module ActiveRecord
|
|
79
79
|
" WHERE table_schema = #{scope[:schema]}" \
|
80
80
|
" AND table_name = #{scope[:name]}" \
|
81
81
|
" AND column_name = #{column_name}"
|
82
|
-
|
82
|
+
# Calling .inspect leads into issues with the query result
|
83
|
+
# which already returns escaped quotes.
|
84
|
+
# We remove the escape sequence from the result in order to deal with double escaping issues.
|
85
|
+
@connection.query_value(sql, "SCHEMA").gsub("\\'", "'").inspect
|
83
86
|
end
|
84
87
|
end
|
85
88
|
end
|
@@ -5,7 +5,7 @@ module ActiveRecord
|
|
5
5
|
class PoolConfig # :nodoc:
|
6
6
|
include Mutex_m
|
7
7
|
|
8
|
-
attr_reader :db_config, :
|
8
|
+
attr_reader :db_config, :connection_klass
|
9
9
|
attr_accessor :schema_cache
|
10
10
|
|
11
11
|
INSTANCES = ObjectSpace::WeakMap.new
|
@@ -17,14 +17,24 @@ module ActiveRecord
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
def initialize(
|
20
|
+
def initialize(connection_klass, db_config)
|
21
21
|
super()
|
22
|
-
@
|
22
|
+
@connection_klass = connection_klass
|
23
23
|
@db_config = db_config
|
24
24
|
@pool = nil
|
25
25
|
INSTANCES[self] = self
|
26
26
|
end
|
27
27
|
|
28
|
+
def connection_specification_name
|
29
|
+
if connection_klass.is_a?(String)
|
30
|
+
connection_klass
|
31
|
+
elsif connection_klass.primary_class?
|
32
|
+
"ActiveRecord::Base"
|
33
|
+
else
|
34
|
+
connection_klass.name
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
28
38
|
def disconnect!
|
29
39
|
ActiveSupport::ForkTracker.check!
|
30
40
|
|
@@ -57,7 +57,7 @@ module ActiveRecord
|
|
57
57
|
ftype = result.ftype i
|
58
58
|
fmod = result.fmod i
|
59
59
|
case type = get_oid_type(ftype, fmod, fname)
|
60
|
-
when Type::Integer, Type::Float,
|
60
|
+
when Type::Integer, Type::Float, OID::Decimal, Type::String, Type::DateTime, Type::Boolean
|
61
61
|
# skip if a column has already been type casted by pg decoders
|
62
62
|
else types[fname] = type
|
63
63
|
end
|
@@ -16,6 +16,14 @@ module ActiveRecord
|
|
16
16
|
super
|
17
17
|
end
|
18
18
|
end
|
19
|
+
|
20
|
+
def type_cast_for_schema(value)
|
21
|
+
case value
|
22
|
+
when ::Float::INFINITY then "::Float::INFINITY"
|
23
|
+
when -::Float::INFINITY then "-::Float::INFINITY"
|
24
|
+
else super
|
25
|
+
end
|
26
|
+
end
|
19
27
|
end
|
20
28
|
end
|
21
29
|
end
|
@@ -26,9 +26,9 @@ module ActiveRecord
|
|
26
26
|
|
27
27
|
value = value.sub(/^\((.+)\)$/, '-\1') # (4)
|
28
28
|
case value
|
29
|
-
when /^-?\D
|
29
|
+
when /^-?\D*+[\d,]+\.\d{2}$/ # (1)
|
30
30
|
value.gsub!(/[^-\d.]/, "")
|
31
|
-
when /^-?\D
|
31
|
+
when /^-?\D*+[\d.]+,\d{2}$/ # (2)
|
32
32
|
value.gsub!(/[^-\d,]/, "").sub!(/,/, ".")
|
33
33
|
end
|
34
34
|
|
@@ -649,9 +649,7 @@ module ActiveRecord
|
|
649
649
|
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
650
650
|
end
|
651
651
|
|
652
|
-
if without_prepared_statement?(binds)
|
653
|
-
result = exec_no_cache(sql, name, [])
|
654
|
-
elsif !prepare
|
652
|
+
if !prepare || without_prepared_statement?(binds)
|
655
653
|
result = exec_no_cache(sql, name, binds)
|
656
654
|
else
|
657
655
|
result = exec_cache(sql, name, binds)
|
@@ -271,7 +271,7 @@ module ActiveRecord
|
|
271
271
|
def change_column(table_name, column_name, type, **options) #:nodoc:
|
272
272
|
alter_table(table_name) do |definition|
|
273
273
|
definition[column_name].instance_eval do
|
274
|
-
self.type = type
|
274
|
+
self.type = aliased_types(type.to_s, type)
|
275
275
|
self.options.merge!(options)
|
276
276
|
end
|
277
277
|
end
|
@@ -91,6 +91,7 @@ module ActiveRecord
|
|
91
91
|
db_config, owner_name = resolve_config_for_connection(database_key)
|
92
92
|
handler = lookup_connection_handler(role.to_sym)
|
93
93
|
|
94
|
+
self.connection_class = true
|
94
95
|
connections << handler.establish_connection(db_config, owner_name: owner_name, role: role)
|
95
96
|
end
|
96
97
|
|
@@ -99,6 +100,7 @@ module ActiveRecord
|
|
99
100
|
db_config, owner_name = resolve_config_for_connection(database_key)
|
100
101
|
handler = lookup_connection_handler(role.to_sym)
|
101
102
|
|
103
|
+
self.connection_class = true
|
102
104
|
connections << handler.establish_connection(db_config, owner_name: owner_name, role: role, shard: shard.to_sym)
|
103
105
|
end
|
104
106
|
end
|
@@ -143,6 +145,10 @@ module ActiveRecord
|
|
143
145
|
if self != Base && !abstract_class
|
144
146
|
raise NotImplementedError, "calling `connected_to` is only allowed on ActiveRecord::Base or abstract classes."
|
145
147
|
end
|
148
|
+
|
149
|
+
if name != connection_specification_name && !primary_class?
|
150
|
+
raise NotImplementedError, "calling `connected_to` is only allowed on the abstract class that established the connection."
|
151
|
+
end
|
146
152
|
end
|
147
153
|
|
148
154
|
if database && (role || shard)
|
@@ -180,12 +186,14 @@ module ActiveRecord
|
|
180
186
|
#
|
181
187
|
# Usage:
|
182
188
|
#
|
183
|
-
# ActiveRecord::Base.
|
189
|
+
# ActiveRecord::Base.connected_to_many(AnimalsRecord, MealsRecord, role: :reading) do
|
184
190
|
# Dog.first # Read from animals replica
|
185
191
|
# Dinner.first # Read from meals replica
|
186
192
|
# Person.first # Read from primary writer
|
187
193
|
# end
|
188
|
-
def connected_to_many(classes, role:, shard: nil, prevent_writes: false)
|
194
|
+
def connected_to_many(*classes, role:, shard: nil, prevent_writes: false)
|
195
|
+
classes = classes.flatten
|
196
|
+
|
189
197
|
if legacy_connection_handling
|
190
198
|
raise NotImplementedError, "connected_to_many is not available with legacy connection handling"
|
191
199
|
end
|
@@ -357,7 +365,7 @@ module ActiveRecord
|
|
357
365
|
self.connection_specification_name = owner_name
|
358
366
|
|
359
367
|
db_config = Base.configurations.resolve(config_or_env)
|
360
|
-
[db_config,
|
368
|
+
[db_config, self]
|
361
369
|
end
|
362
370
|
|
363
371
|
def with_handler(handler_key, &blk)
|
data/lib/active_record/core.rb
CHANGED
@@ -166,10 +166,18 @@ module ActiveRecord
|
|
166
166
|
end
|
167
167
|
|
168
168
|
def self.connection_handlers
|
169
|
+
unless legacy_connection_handling
|
170
|
+
raise NotImplementedError, "The new connection handling does not support accessing multiple connection handlers."
|
171
|
+
end
|
172
|
+
|
169
173
|
@@connection_handlers ||= {}
|
170
174
|
end
|
171
175
|
|
172
176
|
def self.connection_handlers=(handlers)
|
177
|
+
unless legacy_connection_handling
|
178
|
+
raise NotImplementedError, "The new connection handling does not setting support multiple connection handlers."
|
179
|
+
end
|
180
|
+
|
173
181
|
@@connection_handlers = handlers
|
174
182
|
end
|
175
183
|
|
@@ -188,7 +196,7 @@ module ActiveRecord
|
|
188
196
|
else
|
189
197
|
connected_to_stack.reverse_each do |hash|
|
190
198
|
return hash[:role] if hash[:role] && hash[:klasses].include?(Base)
|
191
|
-
return hash[:role] if hash[:role] && hash[:klasses].include?(
|
199
|
+
return hash[:role] if hash[:role] && hash[:klasses].include?(connection_classes)
|
192
200
|
end
|
193
201
|
|
194
202
|
default_role
|
@@ -207,7 +215,7 @@ module ActiveRecord
|
|
207
215
|
def self.current_shard
|
208
216
|
connected_to_stack.reverse_each do |hash|
|
209
217
|
return hash[:shard] if hash[:shard] && hash[:klasses].include?(Base)
|
210
|
-
return hash[:shard] if hash[:shard] && hash[:klasses].include?(
|
218
|
+
return hash[:shard] if hash[:shard] && hash[:klasses].include?(connection_classes)
|
211
219
|
end
|
212
220
|
|
213
221
|
default_shard
|
@@ -229,7 +237,7 @@ module ActiveRecord
|
|
229
237
|
else
|
230
238
|
connected_to_stack.reverse_each do |hash|
|
231
239
|
return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(Base)
|
232
|
-
return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(
|
240
|
+
return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(connection_classes)
|
233
241
|
end
|
234
242
|
|
235
243
|
false
|
@@ -246,11 +254,23 @@ module ActiveRecord
|
|
246
254
|
end
|
247
255
|
end
|
248
256
|
|
249
|
-
def self.
|
257
|
+
def self.connection_class=(b) # :nodoc:
|
258
|
+
@connection_class = b
|
259
|
+
end
|
260
|
+
|
261
|
+
def self.connection_class # :nodoc
|
262
|
+
@connection_class ||= false
|
263
|
+
end
|
264
|
+
|
265
|
+
def self.connection_class? # :nodoc:
|
266
|
+
self.connection_class
|
267
|
+
end
|
268
|
+
|
269
|
+
def self.connection_classes # :nodoc:
|
250
270
|
klass = self
|
251
271
|
|
252
272
|
until klass == Base
|
253
|
-
break if klass.
|
273
|
+
break if klass.connection_class?
|
254
274
|
klass = klass.superclass
|
255
275
|
end
|
256
276
|
|
@@ -269,14 +289,14 @@ module ActiveRecord
|
|
269
289
|
self.default_role = writing_role
|
270
290
|
self.default_shard = :default
|
271
291
|
|
272
|
-
def self.strict_loading_violation!(owner:,
|
292
|
+
def self.strict_loading_violation!(owner:, reflection:) # :nodoc:
|
273
293
|
case action_on_strict_loading_violation
|
274
294
|
when :raise
|
275
|
-
message = "`#{
|
295
|
+
message = "`#{owner}` is marked for strict_loading. The `#{reflection.klass}` association named `:#{reflection.name}` cannot be lazily loaded."
|
276
296
|
raise ActiveRecord::StrictLoadingViolationError.new(message)
|
277
297
|
when :log
|
278
298
|
name = "strict_loading_violation.active_record"
|
279
|
-
ActiveSupport::Notifications.instrument(name, owner: owner,
|
299
|
+
ActiveSupport::Notifications.instrument(name, owner: owner, reflection: reflection)
|
280
300
|
end
|
281
301
|
end
|
282
302
|
end
|
@@ -324,31 +344,37 @@ module ActiveRecord
|
|
324
344
|
hash = args.first
|
325
345
|
return super unless Hash === hash
|
326
346
|
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
347
|
+
hash = hash.each_with_object({}) do |(key, value), h|
|
348
|
+
key = key.to_s
|
349
|
+
key = attribute_aliases[key] || key
|
350
|
+
|
351
|
+
return super if reflect_on_aggregation(key)
|
352
|
+
|
353
|
+
reflection = _reflect_on_association(key)
|
354
|
+
|
355
|
+
if !reflection
|
356
|
+
value = value.id if value.respond_to?(:id)
|
357
|
+
elsif reflection.belongs_to? && !reflection.polymorphic?
|
358
|
+
key = reflection.join_foreign_key
|
359
|
+
pkey = reflection.join_primary_key
|
360
|
+
value = value.public_send(pkey) if value.respond_to?(pkey)
|
340
361
|
end
|
341
|
-
end
|
342
362
|
|
343
|
-
|
363
|
+
if !columns_hash.key?(key) || StatementCache.unsupported_value?(value)
|
364
|
+
return super
|
365
|
+
end
|
366
|
+
|
367
|
+
h[key] = value
|
368
|
+
end
|
344
369
|
|
370
|
+
keys = hash.keys
|
345
371
|
statement = cached_find_by_statement(keys) { |params|
|
346
372
|
wheres = keys.index_with { params.bind }
|
347
373
|
where(wheres).limit(1)
|
348
374
|
}
|
349
375
|
|
350
376
|
begin
|
351
|
-
statement.execute(values, connection).first
|
377
|
+
statement.execute(hash.values, connection).first
|
352
378
|
rescue TypeError
|
353
379
|
raise ActiveRecord::StatementInvalid
|
354
380
|
end
|
@@ -664,14 +690,7 @@ module ActiveRecord
|
|
664
690
|
inspection = if defined?(@attributes) && @attributes
|
665
691
|
self.class.attribute_names.collect do |name|
|
666
692
|
if _has_attribute?(name)
|
667
|
-
|
668
|
-
value = if attr.nil?
|
669
|
-
attr.inspect
|
670
|
-
else
|
671
|
-
attr = format_for_inspect(attr)
|
672
|
-
inspection_filter.filter_param(name, attr)
|
673
|
-
end
|
674
|
-
"#{name}: #{value}"
|
693
|
+
"#{name}: #{attribute_for_inspect(name)}"
|
675
694
|
end
|
676
695
|
end.compact.join(", ")
|
677
696
|
else
|
@@ -42,7 +42,7 @@ module ActiveRecord
|
|
42
42
|
# Return a Hash that can be merged into the main config that represents
|
43
43
|
# the passed in url
|
44
44
|
def build_url_hash
|
45
|
-
if url.nil? || url.start_with?(
|
45
|
+
if url.nil? || %w(jdbc: http: https:).any? { |protocol| url.start_with?(protocol) }
|
46
46
|
{ url: url }
|
47
47
|
else
|
48
48
|
ConnectionUrlResolver.new(url).to_hash
|
data/lib/active_record/enum.rb
CHANGED
@@ -158,8 +158,6 @@ module ActiveRecord
|
|
158
158
|
end
|
159
159
|
|
160
160
|
def enum(definitions)
|
161
|
-
klass = self
|
162
|
-
|
163
161
|
enum_prefix = definitions.delete(:_prefix)
|
164
162
|
enum_suffix = definitions.delete(:_suffix)
|
165
163
|
enum_scopes = definitions.delete(:_scopes)
|
@@ -187,54 +185,77 @@ module ActiveRecord
|
|
187
185
|
EnumType.new(attr, enum_values, subtype)
|
188
186
|
end
|
189
187
|
|
188
|
+
value_method_names = []
|
190
189
|
_enum_methods_module.module_eval do
|
190
|
+
prefix = if enum_prefix == true
|
191
|
+
"#{name}_"
|
192
|
+
elsif enum_prefix
|
193
|
+
"#{enum_prefix}_"
|
194
|
+
end
|
195
|
+
|
196
|
+
suffix = if enum_suffix == true
|
197
|
+
"_#{name}"
|
198
|
+
elsif enum_suffix
|
199
|
+
"_#{enum_suffix}"
|
200
|
+
end
|
201
|
+
|
191
202
|
pairs = values.respond_to?(:each_pair) ? values.each_pair : values.each_with_index
|
192
203
|
pairs.each do |label, value|
|
193
|
-
if enum_prefix == true
|
194
|
-
prefix = "#{name}_"
|
195
|
-
elsif enum_prefix
|
196
|
-
prefix = "#{enum_prefix}_"
|
197
|
-
end
|
198
|
-
if enum_suffix == true
|
199
|
-
suffix = "_#{name}"
|
200
|
-
elsif enum_suffix
|
201
|
-
suffix = "_#{enum_suffix}"
|
202
|
-
end
|
203
|
-
|
204
|
-
method_friendly_label = label.to_s.gsub(/\W+/, "_")
|
205
|
-
value_method_name = "#{prefix}#{method_friendly_label}#{suffix}"
|
206
204
|
enum_values[label] = value
|
207
205
|
label = label.to_s
|
208
206
|
|
209
|
-
|
207
|
+
value_method_name = "#{prefix}#{label}#{suffix}"
|
208
|
+
value_method_names << value_method_name
|
209
|
+
define_enum_methods(name, value_method_name, value, enum_scopes)
|
210
|
+
|
211
|
+
method_friendly_label = label.gsub(/[\W&&[:ascii:]]+/, "_")
|
212
|
+
value_method_alias = "#{prefix}#{method_friendly_label}#{suffix}"
|
213
|
+
|
214
|
+
if value_method_alias != value_method_name && !value_method_names.include?(value_method_alias)
|
215
|
+
value_method_names << value_method_alias
|
216
|
+
define_enum_methods(name, value_method_alias, value, enum_scopes)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
detect_negative_enum_conditions!(value_method_names) if enum_scopes != false
|
221
|
+
enum_values.freeze
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
private
|
226
|
+
class EnumMethods < Module # :nodoc:
|
227
|
+
def initialize(klass)
|
228
|
+
@klass = klass
|
229
|
+
end
|
230
|
+
|
231
|
+
private
|
232
|
+
attr_reader :klass
|
233
|
+
|
234
|
+
def define_enum_methods(name, value_method_name, value, enum_scopes)
|
235
|
+
# def active?() status_for_database == 0 end
|
210
236
|
klass.send(:detect_enum_conflict!, name, "#{value_method_name}?")
|
211
|
-
define_method("#{value_method_name}?") {
|
237
|
+
define_method("#{value_method_name}?") { public_send(:"#{name}_for_database") == value }
|
212
238
|
|
213
239
|
# def active!() update!(status: 0) end
|
214
240
|
klass.send(:detect_enum_conflict!, name, "#{value_method_name}!")
|
215
|
-
define_method("#{value_method_name}!") { update!(
|
241
|
+
define_method("#{value_method_name}!") { update!(name => value) }
|
216
242
|
|
217
243
|
# scope :active, -> { where(status: 0) }
|
218
244
|
# scope :not_active, -> { where.not(status: 0) }
|
219
245
|
if enum_scopes != false
|
220
|
-
klass.send(:detect_negative_condition!, value_method_name)
|
221
|
-
|
222
246
|
klass.send(:detect_enum_conflict!, name, value_method_name, true)
|
223
|
-
klass.scope value_method_name, -> { where(
|
247
|
+
klass.scope value_method_name, -> { where(name => value) }
|
224
248
|
|
225
249
|
klass.send(:detect_enum_conflict!, name, "not_#{value_method_name}", true)
|
226
|
-
klass.scope "not_#{value_method_name}", -> { where.not(
|
250
|
+
klass.scope "not_#{value_method_name}", -> { where.not(name => value) }
|
227
251
|
end
|
228
252
|
end
|
229
|
-
end
|
230
|
-
enum_values.freeze
|
231
253
|
end
|
232
|
-
|
254
|
+
private_constant :EnumMethods
|
233
255
|
|
234
|
-
private
|
235
256
|
def _enum_methods_module
|
236
257
|
@_enum_methods_module ||= begin
|
237
|
-
mod =
|
258
|
+
mod = EnumMethods.new(self)
|
238
259
|
include mod
|
239
260
|
mod
|
240
261
|
end
|
@@ -281,10 +302,16 @@ module ActiveRecord
|
|
281
302
|
}
|
282
303
|
end
|
283
304
|
|
284
|
-
def
|
285
|
-
|
286
|
-
|
287
|
-
|
305
|
+
def detect_negative_enum_conditions!(method_names)
|
306
|
+
return unless logger
|
307
|
+
|
308
|
+
method_names.select { |m| m.start_with?("not_") }.each do |potential_not|
|
309
|
+
inverted_form = potential_not.sub("not_", "")
|
310
|
+
if method_names.include?(inverted_form)
|
311
|
+
logger.warn "Enum element '#{potential_not}' in #{self.name} uses the prefix 'not_'." \
|
312
|
+
" This has caused a conflict with auto generated negative scopes." \
|
313
|
+
" Avoid using enum elements starting with 'not' where the positive form is also an element."
|
314
|
+
end
|
288
315
|
end
|
289
316
|
end
|
290
317
|
end
|