activerecord 6.0.3.5 → 6.0.4.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 +123 -0
- data/README.rdoc +1 -1
- data/lib/active_record/associations/association.rb +2 -3
- data/lib/active_record/associations/association_scope.rb +7 -1
- data/lib/active_record/associations/collection_association.rb +7 -0
- data/lib/active_record/associations/collection_proxy.rb +1 -0
- data/lib/active_record/associations/join_dependency.rb +14 -6
- data/lib/active_record/associations/join_dependency/join_association.rb +7 -0
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/preloader.rb +6 -2
- data/lib/active_record/associations/preloader/association.rb +41 -23
- data/lib/active_record/associations/preloader/through_association.rb +1 -1
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/autosave_association.rb +10 -10
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +6 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +6 -1
- data/lib/active_record/connection_adapters/abstract_adapter.rb +6 -0
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +9 -4
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +8 -4
- 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/range.rb +24 -5
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +2 -1
- data/lib/active_record/core.rb +5 -6
- data/lib/active_record/enum.rb +13 -6
- data/lib/active_record/fixture_set/render_context.rb +1 -1
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/insert_all.rb +1 -1
- data/lib/active_record/locking/optimistic.rb +9 -0
- data/lib/active_record/model_schema.rb +29 -0
- data/lib/active_record/reflection.rb +11 -13
- data/lib/active_record/relation.rb +6 -3
- data/lib/active_record/relation/calculations.rb +1 -1
- data/lib/active_record/relation/delegation.rb +2 -1
- data/lib/active_record/relation/finder_methods.rb +1 -1
- data/lib/active_record/relation/merger.rb +7 -2
- data/lib/active_record/relation/query_methods.rb +23 -11
- data/lib/active_record/scoping/named.rb +5 -0
- data/lib/active_record/test_fixtures.rb +19 -1
- data/lib/active_record/type/time.rb +10 -0
- data/lib/active_record/validations/associated.rb +1 -1
- metadata +13 -13
@@ -1035,6 +1035,12 @@ module ActiveRecord
|
|
1035
1035
|
# In some cases you may want to prevent writes to the database
|
1036
1036
|
# even if you are on a database that can write. `while_preventing_writes`
|
1037
1037
|
# will prevent writes to the database for the duration of the block.
|
1038
|
+
#
|
1039
|
+
# This method does not provide the same protection as a readonly
|
1040
|
+
# user and is meant to be a safeguard against accidental writes.
|
1041
|
+
#
|
1042
|
+
# See `READ_QUERY` for the queries that are blocked by this
|
1043
|
+
# method.
|
1038
1044
|
def while_preventing_writes(enabled = true)
|
1039
1045
|
original, self.prevent_writes = self.prevent_writes, enabled
|
1040
1046
|
yield
|
@@ -63,6 +63,10 @@ module ActiveRecord
|
|
63
63
|
end
|
64
64
|
CODE
|
65
65
|
end
|
66
|
+
|
67
|
+
def aliased_types(name, fallback)
|
68
|
+
"timestamp" == name ? :datetime : fallback
|
69
|
+
end
|
66
70
|
end
|
67
71
|
|
68
72
|
AddColumnDefinition = Struct.new(:column) # :nodoc:
|
@@ -105,8 +109,9 @@ module ActiveRecord
|
|
105
109
|
!ActiveRecord::SchemaDumper.fk_ignore_pattern.match?(name) if name
|
106
110
|
end
|
107
111
|
|
108
|
-
def defined_for?(to_table: nil, **options)
|
112
|
+
def defined_for?(to_table: nil, validate: nil, **options)
|
109
113
|
(to_table.nil? || to_table.to_s == self.to_table) &&
|
114
|
+
(validate.nil? || validate == options.fetch(:validate, validate)) &&
|
110
115
|
options.all? { |k, v| self.options[k].to_s == v.to_s }
|
111
116
|
end
|
112
117
|
|
@@ -103,7 +103,11 @@ module ActiveRecord
|
|
103
103
|
end
|
104
104
|
end
|
105
105
|
|
106
|
+
DEFAULT_READ_QUERY = [:begin, :commit, :explain, :release, :rollback, :savepoint, :select, :with] # :nodoc:
|
107
|
+
private_constant :DEFAULT_READ_QUERY
|
108
|
+
|
106
109
|
def self.build_read_query_regexp(*parts) # :nodoc:
|
110
|
+
parts += DEFAULT_READ_QUERY
|
107
111
|
parts = parts.map { |part| /#{part}/i }
|
108
112
|
/\A(?:[\(\s]|#{COMMENT_REGEX})*#{Regexp.union(*parts)}/
|
109
113
|
end
|
@@ -168,6 +172,8 @@ module ActiveRecord
|
|
168
172
|
spec_name = conn.pool.spec.name
|
169
173
|
name = "#{spec_name}::SchemaMigration"
|
170
174
|
|
175
|
+
return ActiveRecord::SchemaMigration if spec_name == "primary"
|
176
|
+
|
171
177
|
Class.new(ActiveRecord::SchemaMigration) do
|
172
178
|
define_singleton_method(:name) { name }
|
173
179
|
define_singleton_method(:to_s) { name }
|
@@ -675,9 +675,10 @@ module ActiveRecord
|
|
675
675
|
end
|
676
676
|
|
677
677
|
def add_index_for_alter(table_name, column_name, options = {})
|
678
|
-
index_name, index_type, index_columns, _, index_algorithm, index_using = add_index_options(table_name, column_name, **options)
|
678
|
+
index_name, index_type, index_columns, _, index_algorithm, index_using, comment = add_index_options(table_name, column_name, **options)
|
679
679
|
index_algorithm[0, 0] = ", " if index_algorithm.present?
|
680
|
-
"ADD #{index_type} INDEX #{quote_column_name(index_name)} #{index_using} (#{index_columns})#{index_algorithm}"
|
680
|
+
sql = +"ADD #{index_type} INDEX #{quote_column_name(index_name)} #{index_using} (#{index_columns})#{index_algorithm}"
|
681
|
+
add_sql_comment!(sql, comment)
|
681
682
|
end
|
682
683
|
|
683
684
|
def remove_index_for_alter(table_name, options = {})
|
@@ -686,7 +687,11 @@ module ActiveRecord
|
|
686
687
|
end
|
687
688
|
|
688
689
|
def supports_rename_index?
|
689
|
-
mariadb?
|
690
|
+
if mariadb?
|
691
|
+
database_version >= "10.5.2"
|
692
|
+
else
|
693
|
+
database_version >= "5.7.6"
|
694
|
+
end
|
690
695
|
end
|
691
696
|
|
692
697
|
def configure_connection
|
@@ -739,7 +744,7 @@ module ActiveRecord
|
|
739
744
|
end.compact.join(", ")
|
740
745
|
|
741
746
|
# ...and send them all in one query
|
742
|
-
execute
|
747
|
+
execute("SET #{encoding} #{sql_mode_assignment} #{variable_assignments}", "SCHEMA")
|
743
748
|
end
|
744
749
|
|
745
750
|
def column_definitions(table_name) # :nodoc:
|
@@ -20,7 +20,7 @@ module ActiveRecord
|
|
20
20
|
end
|
21
21
|
|
22
22
|
READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
|
23
|
-
:
|
23
|
+
:desc, :describe, :set, :show, :use
|
24
24
|
) # :nodoc:
|
25
25
|
private_constant :READ_QUERY
|
26
26
|
|
@@ -203,10 +203,14 @@ module ActiveRecord
|
|
203
203
|
def data_source_sql(name = nil, type: nil)
|
204
204
|
scope = quoted_scope(name, type: type)
|
205
205
|
|
206
|
-
sql = +"SELECT table_name FROM information_schema.tables"
|
207
|
-
sql << " WHERE table_schema = #{scope[:schema]}"
|
208
|
-
|
209
|
-
|
206
|
+
sql = +"SELECT table_name FROM (SELECT * FROM information_schema.tables "
|
207
|
+
sql << " WHERE table_schema = #{scope[:schema]}) _subquery"
|
208
|
+
if scope[:type] || scope[:name]
|
209
|
+
conditions = []
|
210
|
+
conditions << "_subquery.table_type = #{scope[:type]}" if scope[:type]
|
211
|
+
conditions << "_subquery.table_name = #{scope[:name]}" if scope[:name]
|
212
|
+
sql << " WHERE #{conditions.join(" AND ")}"
|
213
|
+
end
|
210
214
|
sql
|
211
215
|
end
|
212
216
|
|
@@ -68,7 +68,7 @@ module ActiveRecord
|
|
68
68
|
end
|
69
69
|
|
70
70
|
READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
|
71
|
-
:
|
71
|
+
:close, :declare, :fetch, :move, :set, :show
|
72
72
|
) # :nodoc:
|
73
73
|
private_constant :READ_QUERY
|
74
74
|
|
@@ -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
|
@@ -67,15 +67,34 @@ module ActiveRecord
|
|
67
67
|
end
|
68
68
|
|
69
69
|
def extract_bounds(value)
|
70
|
-
from, to = value[1..-2].split(",")
|
70
|
+
from, to = value[1..-2].split(",", 2)
|
71
71
|
{
|
72
|
-
from: (
|
73
|
-
to: (
|
74
|
-
exclude_start: (
|
75
|
-
exclude_end: (
|
72
|
+
from: (from == "" || from == "-infinity") ? infinity(negative: true) : unquote(from),
|
73
|
+
to: (to == "" || to == "infinity") ? infinity : unquote(to),
|
74
|
+
exclude_start: value.start_with?("("),
|
75
|
+
exclude_end: value.end_with?(")")
|
76
76
|
}
|
77
77
|
end
|
78
78
|
|
79
|
+
# When formatting the bound values of range types, PostgreSQL quotes
|
80
|
+
# the bound value using double-quotes in certain conditions. Within
|
81
|
+
# a double-quoted string, literal " and \ characters are themselves
|
82
|
+
# escaped. In input, PostgreSQL accepts multiple escape styles for "
|
83
|
+
# (either \" or "") but in output always uses "".
|
84
|
+
# See:
|
85
|
+
# * https://www.postgresql.org/docs/current/rangetypes.html#RANGETYPES-IO
|
86
|
+
# * https://www.postgresql.org/docs/current/rowtypes.html#ROWTYPES-IO-SYNTAX
|
87
|
+
def unquote(value)
|
88
|
+
if value.start_with?('"') && value.end_with?('"')
|
89
|
+
unquoted_value = value[1..-2]
|
90
|
+
unquoted_value.gsub!('""', '"')
|
91
|
+
unquoted_value.gsub!('\\\\', '\\')
|
92
|
+
unquoted_value
|
93
|
+
else
|
94
|
+
value
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
79
98
|
def infinity(negative: false)
|
80
99
|
if subtype.respond_to?(:infinity)
|
81
100
|
subtype.infinity(negative: negative)
|
@@ -5,7 +5,7 @@ module ActiveRecord
|
|
5
5
|
module SQLite3
|
6
6
|
module DatabaseStatements
|
7
7
|
READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
|
8
|
-
:
|
8
|
+
:pragma
|
9
9
|
) # :nodoc:
|
10
10
|
private_constant :READ_QUERY
|
11
11
|
|
@@ -61,7 +61,7 @@ module ActiveRecord
|
|
61
61
|
|
62
62
|
def remove_foreign_key(from_table, to_table = nil, **options)
|
63
63
|
to_table ||= options[:to_table]
|
64
|
-
options = options.except(:name, :to_table)
|
64
|
+
options = options.except(:name, :to_table, :validate)
|
65
65
|
foreign_keys = foreign_keys(from_table)
|
66
66
|
|
67
67
|
fkey = foreign_keys.detect do |fk|
|
@@ -283,13 +283,14 @@ module ActiveRecord
|
|
283
283
|
def change_column(table_name, column_name, type, options = {}) #:nodoc:
|
284
284
|
alter_table(table_name) do |definition|
|
285
285
|
definition[column_name].instance_eval do
|
286
|
-
self.type = type
|
286
|
+
self.type = aliased_types(type.to_s, type)
|
287
287
|
self.limit = options[:limit] if options.include?(:limit)
|
288
288
|
self.default = options[:default] if options.include?(:default)
|
289
289
|
self.null = options[:null] if options.include?(:null)
|
290
290
|
self.precision = options[:precision] if options.include?(:precision)
|
291
291
|
self.scale = options[:scale] if options.include?(:scale)
|
292
292
|
self.collation = options[:collation] if options.include?(:collation)
|
293
|
+
self.options.merge!(options)
|
293
294
|
end
|
294
295
|
end
|
295
296
|
end
|
data/lib/active_record/core.rb
CHANGED
@@ -285,18 +285,17 @@ module ActiveRecord
|
|
285
285
|
false
|
286
286
|
end
|
287
287
|
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
end
|
288
|
+
def cached_find_by_statement(key, &block) # :nodoc:
|
289
|
+
cache = @find_by_statement_cache[connection.prepared_statements]
|
290
|
+
cache.compute_if_absent(key) { StatementCache.create(connection, &block) }
|
291
|
+
end
|
293
292
|
|
293
|
+
private
|
294
294
|
def relation
|
295
295
|
relation = Relation.create(self)
|
296
296
|
|
297
297
|
if finder_needs_type_condition? && !ignore_default_scope?
|
298
298
|
relation.where!(type_condition)
|
299
|
-
relation.create_with!(inheritance_column.to_s => sti_name)
|
300
299
|
else
|
301
300
|
relation
|
302
301
|
end
|
data/lib/active_record/enum.rb
CHANGED
@@ -173,6 +173,7 @@ module ActiveRecord
|
|
173
173
|
|
174
174
|
_enum_methods_module.module_eval do
|
175
175
|
pairs = values.respond_to?(:each_pair) ? values.each_pair : values.each_with_index
|
176
|
+
value_method_names = []
|
176
177
|
pairs.each do |label, value|
|
177
178
|
if enum_prefix == true
|
178
179
|
prefix = "#{name}_"
|
@@ -186,6 +187,7 @@ module ActiveRecord
|
|
186
187
|
end
|
187
188
|
|
188
189
|
value_method_name = "#{prefix}#{label}#{suffix}"
|
190
|
+
value_method_names << value_method_name
|
189
191
|
enum_values[label] = value
|
190
192
|
label = label.to_s
|
191
193
|
|
@@ -200,8 +202,6 @@ module ActiveRecord
|
|
200
202
|
# scope :active, -> { where(status: 0) }
|
201
203
|
# scope :not_active, -> { where.not(status: 0) }
|
202
204
|
if enum_scopes != false
|
203
|
-
klass.send(:detect_negative_condition!, value_method_name)
|
204
|
-
|
205
205
|
klass.send(:detect_enum_conflict!, name, value_method_name, true)
|
206
206
|
klass.scope value_method_name, -> { where(attr => value) }
|
207
207
|
|
@@ -209,6 +209,7 @@ module ActiveRecord
|
|
209
209
|
klass.scope "not_#{value_method_name}", -> { where.not(attr => value) }
|
210
210
|
end
|
211
211
|
end
|
212
|
+
klass.send(:detect_negative_enum_conditions!, value_method_names) if enum_scopes != false
|
212
213
|
end
|
213
214
|
enum_values.freeze
|
214
215
|
end
|
@@ -264,10 +265,16 @@ module ActiveRecord
|
|
264
265
|
}
|
265
266
|
end
|
266
267
|
|
267
|
-
def
|
268
|
-
|
269
|
-
|
270
|
-
|
268
|
+
def detect_negative_enum_conditions!(method_names)
|
269
|
+
return unless logger
|
270
|
+
|
271
|
+
method_names.select { |m| m.start_with?("not_") }.each do |potential_not|
|
272
|
+
inverted_form = potential_not.sub("not_", "")
|
273
|
+
if method_names.include?(inverted_form)
|
274
|
+
logger.warn "Enum element '#{potential_not}' in #{self.name} uses the prefix 'not_'." \
|
275
|
+
" This has caused a conflict with auto generated negative scopes." \
|
276
|
+
" Avoid using enum elements starting with 'not' where the positive form is also an element."
|
277
|
+
end
|
271
278
|
end
|
272
279
|
end
|
273
280
|
end
|
@@ -60,6 +60,15 @@ module ActiveRecord
|
|
60
60
|
self.class.locking_enabled?
|
61
61
|
end
|
62
62
|
|
63
|
+
def increment!(*, **) #:nodoc:
|
64
|
+
super.tap do
|
65
|
+
if locking_enabled?
|
66
|
+
self[self.class.locking_column] += 1
|
67
|
+
clear_attribute_change(self.class.locking_column)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
63
72
|
private
|
64
73
|
def _create_record(attribute_names = self.attribute_names)
|
65
74
|
if locking_enabled?
|
@@ -287,6 +287,35 @@ module ActiveRecord
|
|
287
287
|
|
288
288
|
# Sets the columns names the model should ignore. Ignored columns won't have attribute
|
289
289
|
# accessors defined, and won't be referenced in SQL queries.
|
290
|
+
#
|
291
|
+
# A common usage pattern for this method is to ensure all references to an attribute
|
292
|
+
# have been removed and deployed, before a migration to drop the column from the database
|
293
|
+
# has been deployed and run. Using this two step approach to dropping columns ensures there
|
294
|
+
# is no code that raises errors due to having a cached schema in memory at the time the
|
295
|
+
# schema migration is run.
|
296
|
+
#
|
297
|
+
# For example, given a model where you want to drop the "category" attribute, first mark it
|
298
|
+
# as ignored:
|
299
|
+
#
|
300
|
+
# class Project < ActiveRecord::Base
|
301
|
+
# # schema:
|
302
|
+
# # id :bigint
|
303
|
+
# # name :string, limit: 255
|
304
|
+
# # category :string, limit: 255
|
305
|
+
#
|
306
|
+
# self.ignored_columns = [:category]
|
307
|
+
# end
|
308
|
+
#
|
309
|
+
# The schema still contains `category`, but now the model omits it, so any meta-driven code or
|
310
|
+
# schema caching will not attempt to use the column:
|
311
|
+
#
|
312
|
+
# Project.columns_hash["category"] => nil
|
313
|
+
#
|
314
|
+
# You will get an error if accessing that attribute directly, so ensure all usages of the
|
315
|
+
# column are removed (automated tests can help you find any usages).
|
316
|
+
#
|
317
|
+
# user = Project.create!(name: "First Project")
|
318
|
+
# user.category # => raises NoMethodError
|
290
319
|
def ignored_columns=(columns)
|
291
320
|
@ignored_columns = columns.map(&:to_s)
|
292
321
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_support/core_ext/string/filters"
|
4
|
-
require "concurrent/map"
|
5
4
|
|
6
5
|
module ActiveRecord
|
7
6
|
# = Active Record Reflection
|
@@ -201,9 +200,9 @@ module ActiveRecord
|
|
201
200
|
klass_scope
|
202
201
|
end
|
203
202
|
|
204
|
-
def join_scopes(table, predicate_builder) # :nodoc:
|
203
|
+
def join_scopes(table, predicate_builder, klass = self.klass) # :nodoc:
|
205
204
|
if scope
|
206
|
-
[scope_for(build_scope(table, predicate_builder))]
|
205
|
+
[scope_for(build_scope(table, predicate_builder, klass))]
|
207
206
|
else
|
208
207
|
[]
|
209
208
|
end
|
@@ -292,7 +291,7 @@ module ActiveRecord
|
|
292
291
|
JoinKeys.new(join_primary_key(association_klass), join_foreign_key)
|
293
292
|
end
|
294
293
|
|
295
|
-
def build_scope(table, predicate_builder = predicate_builder(table))
|
294
|
+
def build_scope(table, predicate_builder = predicate_builder(table), klass = self.klass)
|
296
295
|
Relation.create(
|
297
296
|
klass,
|
298
297
|
table: table,
|
@@ -432,19 +431,18 @@ module ActiveRecord
|
|
432
431
|
@type = options[:as] && (options[:foreign_type] || "#{options[:as]}_type")
|
433
432
|
@foreign_type = options[:polymorphic] && (options[:foreign_type] || "#{name}_type")
|
434
433
|
@constructable = calculate_constructable(macro, options)
|
435
|
-
@association_scope_cache = Concurrent::Map.new
|
436
434
|
|
437
435
|
if options[:class_name] && options[:class_name].class == Class
|
438
436
|
raise ArgumentError, "A class was passed to `:class_name` but we are expecting a string."
|
439
437
|
end
|
440
438
|
end
|
441
439
|
|
442
|
-
def association_scope_cache(
|
443
|
-
key =
|
440
|
+
def association_scope_cache(klass, owner, &block)
|
441
|
+
key = self
|
444
442
|
if polymorphic?
|
445
443
|
key = [key, owner._read_attribute(@foreign_type)]
|
446
444
|
end
|
447
|
-
|
445
|
+
klass.cached_find_by_statement(key, &block)
|
448
446
|
end
|
449
447
|
|
450
448
|
def constructable? # :nodoc:
|
@@ -510,7 +508,7 @@ module ActiveRecord
|
|
510
508
|
# This is for clearing cache on the reflection. Useful for tests that need to compare
|
511
509
|
# SQL queries on associations.
|
512
510
|
def clear_association_scope_cache # :nodoc:
|
513
|
-
|
511
|
+
klass.initialize_find_by_cache
|
514
512
|
end
|
515
513
|
|
516
514
|
def nested?
|
@@ -839,8 +837,8 @@ module ActiveRecord
|
|
839
837
|
source_reflection.scopes + super
|
840
838
|
end
|
841
839
|
|
842
|
-
def join_scopes(table, predicate_builder) # :nodoc:
|
843
|
-
source_reflection.join_scopes(table, predicate_builder) + super
|
840
|
+
def join_scopes(table, predicate_builder, klass = self.klass) # :nodoc:
|
841
|
+
source_reflection.join_scopes(table, predicate_builder, klass) + super
|
844
842
|
end
|
845
843
|
|
846
844
|
def has_scope?
|
@@ -1003,9 +1001,9 @@ module ActiveRecord
|
|
1003
1001
|
@previous_reflection = previous_reflection
|
1004
1002
|
end
|
1005
1003
|
|
1006
|
-
def join_scopes(table, predicate_builder) # :nodoc:
|
1004
|
+
def join_scopes(table, predicate_builder, klass = self.klass) # :nodoc:
|
1007
1005
|
scopes = @previous_reflection.join_scopes(table, predicate_builder) + super
|
1008
|
-
scopes << build_scope(table, predicate_builder).instance_exec(nil, &source_type_scope)
|
1006
|
+
scopes << build_scope(table, predicate_builder, klass).instance_exec(nil, &source_type_scope)
|
1009
1007
|
end
|
1010
1008
|
|
1011
1009
|
def constraints
|