activerecord 5.0.0 → 5.0.7.2
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 +5 -5
- data/CHANGELOG.md +431 -2
- data/README.rdoc +1 -1
- data/lib/active_record/aggregations.rb +4 -2
- data/lib/active_record/association_relation.rb +4 -1
- data/lib/active_record/associations/association.rb +11 -1
- data/lib/active_record/associations/association_scope.rb +1 -1
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +4 -2
- data/lib/active_record/associations/builder/singular_association.rb +10 -1
- data/lib/active_record/associations/collection_association.rb +56 -48
- data/lib/active_record/associations/collection_proxy.rb +38 -20
- data/lib/active_record/associations/has_many_association.rb +1 -7
- data/lib/active_record/associations/has_many_through_association.rb +2 -4
- data/lib/active_record/associations/join_dependency/join_association.rb +6 -11
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/join_dependency.rb +10 -4
- data/lib/active_record/associations/preloader/association.rb +24 -37
- data/lib/active_record/associations/preloader/collection_association.rb +0 -1
- data/lib/active_record/associations/preloader/singular_association.rb +0 -1
- data/lib/active_record/associations/preloader/through_association.rb +10 -4
- data/lib/active_record/associations/singular_association.rb +8 -2
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +38 -17
- data/lib/active_record/attribute.rb +3 -3
- data/lib/active_record/attribute_methods/primary_key.rb +14 -1
- data/lib/active_record/attribute_methods/read.rb +1 -1
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +2 -2
- data/lib/active_record/attribute_methods.rb +3 -7
- data/lib/active_record/attribute_set/builder.rb +37 -13
- data/lib/active_record/attribute_set.rb +2 -0
- data/lib/active_record/attributes.rb +3 -3
- data/lib/active_record/autosave_association.rb +15 -11
- data/lib/active_record/base.rb +1 -1
- data/lib/active_record/collection_cache_key.rb +16 -6
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +41 -33
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +37 -2
- data/lib/active_record/connection_adapters/abstract/quoting.rb +14 -5
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +11 -14
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +68 -56
- data/lib/active_record/connection_adapters/abstract_adapter.rb +36 -12
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +63 -60
- data/lib/active_record/connection_adapters/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +8 -25
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +2 -6
- data/lib/active_record/connection_adapters/postgresql/column.rb +28 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +12 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +10 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +32 -3
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +18 -8
- data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +25 -19
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +4 -4
- data/lib/active_record/core.rb +6 -4
- data/lib/active_record/enum.rb +8 -5
- data/lib/active_record/explain.rb +20 -9
- data/lib/active_record/fixtures.rb +5 -5
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/integration.rb +13 -10
- data/lib/active_record/log_subscriber.rb +19 -17
- data/lib/active_record/migration.rb +35 -14
- data/lib/active_record/model_schema.rb +161 -52
- data/lib/active_record/no_touching.rb +4 -0
- data/lib/active_record/persistence.rb +41 -20
- data/lib/active_record/query_cache.rb +15 -17
- data/lib/active_record/querying.rb +3 -3
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +9 -21
- data/lib/active_record/reflection.rb +20 -0
- data/lib/active_record/relation/batches.rb +10 -10
- data/lib/active_record/relation/calculations.rb +16 -12
- data/lib/active_record/relation/delegation.rb +2 -1
- data/lib/active_record/relation/finder_methods.rb +13 -11
- data/lib/active_record/relation/query_methods.rb +3 -3
- data/lib/active_record/relation.rb +12 -5
- data/lib/active_record/result.rb +7 -1
- data/lib/active_record/sanitization.rb +11 -1
- data/lib/active_record/schema_dumper.rb +10 -17
- data/lib/active_record/scoping/default.rb +5 -1
- data/lib/active_record/scoping/named.rb +18 -6
- data/lib/active_record/scoping.rb +4 -3
- data/lib/active_record/serialization.rb +1 -1
- data/lib/active_record/statement_cache.rb +2 -2
- data/lib/active_record/table_metadata.rb +4 -3
- data/lib/active_record/tasks/database_tasks.rb +14 -11
- data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
- data/lib/active_record/touch_later.rb +6 -1
- data/lib/active_record/transactions.rb +1 -1
- data/lib/active_record/type/internal/abstract_json.rb +5 -1
- data/lib/active_record/validations/uniqueness.rb +3 -4
- data/lib/active_record.rb +3 -2
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -1
- data/lib/rails/generators/active_record/migration.rb +8 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
- metadata +7 -8
@@ -30,11 +30,11 @@ module ActiveRecord
|
|
30
30
|
# end
|
31
31
|
#
|
32
32
|
# ==== Options
|
33
|
-
# * <tt>:batch_size</tt> - Specifies the size of the batch.
|
33
|
+
# * <tt>:batch_size</tt> - Specifies the size of the batch. Defaults to 1000.
|
34
34
|
# * <tt>:start</tt> - Specifies the primary key value to start from, inclusive of the value.
|
35
35
|
# * <tt>:finish</tt> - Specifies the primary key value to end at, inclusive of the value.
|
36
36
|
# * <tt>:error_on_ignore</tt> - Overrides the application config to specify if an error should be raised when
|
37
|
-
#
|
37
|
+
# the order and limit have to be ignored due to batching.
|
38
38
|
#
|
39
39
|
# This is especially useful if you want multiple workers dealing with
|
40
40
|
# the same processing queue. You can make worker 1 handle all the records
|
@@ -85,11 +85,11 @@ module ActiveRecord
|
|
85
85
|
# To be yielded each record one by one, use #find_each instead.
|
86
86
|
#
|
87
87
|
# ==== Options
|
88
|
-
# * <tt>:batch_size</tt> - Specifies the size of the batch.
|
88
|
+
# * <tt>:batch_size</tt> - Specifies the size of the batch. Defaults to 1000.
|
89
89
|
# * <tt>:start</tt> - Specifies the primary key value to start from, inclusive of the value.
|
90
90
|
# * <tt>:finish</tt> - Specifies the primary key value to end at, inclusive of the value.
|
91
91
|
# * <tt>:error_on_ignore</tt> - Overrides the application config to specify if an error should be raised when
|
92
|
-
#
|
92
|
+
# the order and limit have to be ignored due to batching.
|
93
93
|
#
|
94
94
|
# This is especially useful if you want multiple workers dealing with
|
95
95
|
# the same processing queue. You can make worker 1 handle all the records
|
@@ -132,9 +132,9 @@ module ActiveRecord
|
|
132
132
|
# If you do not provide a block to #in_batches, it will return a
|
133
133
|
# BatchEnumerator which is enumerable.
|
134
134
|
#
|
135
|
-
# Person.in_batches.
|
135
|
+
# Person.in_batches.each_with_index do |relation, batch_index|
|
136
136
|
# puts "Processing relation ##{batch_index}"
|
137
|
-
# relation.
|
137
|
+
# relation.delete_all
|
138
138
|
# end
|
139
139
|
#
|
140
140
|
# Examples of calling methods on the returned BatchEnumerator object:
|
@@ -144,12 +144,12 @@ module ActiveRecord
|
|
144
144
|
# Person.in_batches.each_record(&:party_all_night!)
|
145
145
|
#
|
146
146
|
# ==== Options
|
147
|
-
# * <tt>:of</tt> - Specifies the size of the batch.
|
148
|
-
# * <tt>:load</tt> - Specifies if the relation should be loaded.
|
147
|
+
# * <tt>:of</tt> - Specifies the size of the batch. Defaults to 1000.
|
148
|
+
# * <tt>:load</tt> - Specifies if the relation should be loaded. Defaults to false.
|
149
149
|
# * <tt>:start</tt> - Specifies the primary key value to start from, inclusive of the value.
|
150
150
|
# * <tt>:finish</tt> - Specifies the primary key value to end at, inclusive of the value.
|
151
151
|
# * <tt>:error_on_ignore</tt> - Overrides the application config to specify if an error should be raised when
|
152
|
-
#
|
152
|
+
# the order and limit have to be ignored due to batching.
|
153
153
|
#
|
154
154
|
# This is especially useful if you want to work with the
|
155
155
|
# ActiveRecord::Relation object instead of the array of records, or if
|
@@ -176,7 +176,7 @@ module ActiveRecord
|
|
176
176
|
#
|
177
177
|
# NOTE: It's not possible to set the order. That is automatically set to
|
178
178
|
# ascending on the primary key ("id ASC") to make the batch ordering
|
179
|
-
# consistent. Therefore the primary key must be orderable, e.g an integer
|
179
|
+
# consistent. Therefore the primary key must be orderable, e.g. an integer
|
180
180
|
# or a string.
|
181
181
|
#
|
182
182
|
# NOTE: You can't set the limit either, that's used to control the batch
|
@@ -113,7 +113,10 @@ module ActiveRecord
|
|
113
113
|
end
|
114
114
|
|
115
115
|
if has_include?(column_name)
|
116
|
-
construct_relation_for_association_calculations
|
116
|
+
relation = construct_relation_for_association_calculations
|
117
|
+
relation = relation.distinct if operation.to_s.downcase == "count"
|
118
|
+
|
119
|
+
relation.calculate(operation, column_name)
|
117
120
|
else
|
118
121
|
perform_calculation(operation, column_name)
|
119
122
|
end
|
@@ -156,7 +159,7 @@ module ActiveRecord
|
|
156
159
|
#
|
157
160
|
def pluck(*column_names)
|
158
161
|
if loaded? && (column_names.map(&:to_s) - @klass.attribute_names - @klass.attribute_aliases.keys).empty?
|
159
|
-
return
|
162
|
+
return records.pluck(*column_names)
|
160
163
|
end
|
161
164
|
|
162
165
|
if has_include?(column_names.first)
|
@@ -194,11 +197,6 @@ module ActiveRecord
|
|
194
197
|
|
195
198
|
if operation == "count"
|
196
199
|
column_name ||= select_for_count
|
197
|
-
|
198
|
-
unless arel.ast.grep(Arel::Nodes::OuterJoin).empty?
|
199
|
-
distinct = true
|
200
|
-
end
|
201
|
-
|
202
200
|
column_name = primary_key if column_name == :all && distinct
|
203
201
|
distinct = nil if column_name =~ /\s*DISTINCT[\s(]+/i
|
204
202
|
end
|
@@ -240,6 +238,10 @@ module ActiveRecord
|
|
240
238
|
|
241
239
|
select_value = operation_over_aggregate_column(column, operation, distinct)
|
242
240
|
|
241
|
+
if operation == "sum" && distinct
|
242
|
+
select_value.distinct = true
|
243
|
+
end
|
244
|
+
|
243
245
|
column_alias = select_value.alias
|
244
246
|
column_alias ||= @klass.connection.column_name_for_operation(operation, select_value)
|
245
247
|
relation.select_values = [select_value]
|
@@ -284,7 +286,7 @@ module ActiveRecord
|
|
284
286
|
operation,
|
285
287
|
distinct).as(aggregate_alias)
|
286
288
|
]
|
287
|
-
select_values += select_values unless having_clause.empty?
|
289
|
+
select_values += self.select_values unless having_clause.empty?
|
288
290
|
|
289
291
|
select_values.concat group_columns.map { |aliaz, field|
|
290
292
|
if field.respond_to?(:as)
|
@@ -308,8 +310,10 @@ module ActiveRecord
|
|
308
310
|
|
309
311
|
Hash[calculated_data.map do |row|
|
310
312
|
key = group_columns.map { |aliaz, col_name|
|
311
|
-
column =
|
312
|
-
|
313
|
+
column = type_for(col_name) do
|
314
|
+
calculated_data.column_types.fetch(aliaz) do
|
315
|
+
Type::Value.new
|
316
|
+
end
|
313
317
|
end
|
314
318
|
type_cast_calculated_value(row[aliaz], column)
|
315
319
|
}
|
@@ -342,9 +346,9 @@ module ActiveRecord
|
|
342
346
|
@klass.connection.table_alias_for(table_name)
|
343
347
|
end
|
344
348
|
|
345
|
-
def type_for(field)
|
349
|
+
def type_for(field, &block)
|
346
350
|
field_name = field.respond_to?(:name) ? field.name.to_s : field.to_s.split('.').last
|
347
|
-
@klass.type_for_attribute(field_name)
|
351
|
+
@klass.type_for_attribute(field_name, &block)
|
348
352
|
end
|
349
353
|
|
350
354
|
def type_cast_calculated_value(value, type, operation = nil)
|
@@ -37,7 +37,8 @@ module ActiveRecord
|
|
37
37
|
|
38
38
|
delegate :to_xml, :encode_with, :length, :collect, :map, :each, :all?, :include?, :to_ary, :join,
|
39
39
|
:[], :&, :|, :+, :-, :sample, :reverse, :compact, :in_groups, :in_groups_of,
|
40
|
-
:
|
40
|
+
:to_sentence, :to_formatted_s,
|
41
|
+
:shuffle, :split, :index, to: :records
|
41
42
|
|
42
43
|
delegate :table_name, :quoted_table_name, :primary_key, :quoted_primary_key,
|
43
44
|
:connection, :columns_hash, :to => :klass
|
@@ -17,8 +17,8 @@ module ActiveRecord
|
|
17
17
|
# Person.where("administrator = 1").order("created_on DESC").find(1)
|
18
18
|
#
|
19
19
|
# NOTE: The returned records may not be in the same order as the ids you
|
20
|
-
# provide since database rows are unordered. You
|
21
|
-
# option if you want the results
|
20
|
+
# provide since database rows are unordered. You will need to provide an explicit QueryMethods#order
|
21
|
+
# option if you want the results to be sorted.
|
22
22
|
#
|
23
23
|
# ==== Find with lock
|
24
24
|
#
|
@@ -343,18 +343,20 @@ module ActiveRecord
|
|
343
343
|
# of results obtained should be provided in the +result_size+ argument and
|
344
344
|
# the expected number of results should be provided in the +expected_size+
|
345
345
|
# argument.
|
346
|
-
def raise_record_not_found_exception!(ids, result_size, expected_size) #:nodoc:
|
346
|
+
def raise_record_not_found_exception!(ids, result_size, expected_size, key = primary_key) #:nodoc:
|
347
347
|
conditions = arel.where_sql(@klass.arel_engine)
|
348
348
|
conditions = " [#{conditions}]" if conditions
|
349
|
+
name = @klass.name
|
349
350
|
|
350
351
|
if Array(ids).size == 1
|
351
|
-
error = "Couldn't find #{
|
352
|
+
error = "Couldn't find #{name} with '#{key}'=#{ids}#{conditions}"
|
353
|
+
raise RecordNotFound.new(error, name, key, ids)
|
352
354
|
else
|
353
|
-
error = "Couldn't find all #{
|
355
|
+
error = "Couldn't find all #{name.pluralize} with '#{key}': "
|
354
356
|
error << "(#{ids.join(", ")})#{conditions} (found #{result_size} results, but was looking for #{expected_size})"
|
355
|
-
end
|
356
357
|
|
357
|
-
|
358
|
+
raise RecordNotFound, error
|
359
|
+
end
|
358
360
|
end
|
359
361
|
|
360
362
|
private
|
@@ -520,7 +522,7 @@ module ActiveRecord
|
|
520
522
|
|
521
523
|
def find_take
|
522
524
|
if loaded?
|
523
|
-
|
525
|
+
records.first
|
524
526
|
else
|
525
527
|
@take ||= limit(1).records.first
|
526
528
|
end
|
@@ -537,7 +539,7 @@ module ActiveRecord
|
|
537
539
|
MSG
|
538
540
|
end
|
539
541
|
if loaded?
|
540
|
-
|
542
|
+
records[index]
|
541
543
|
else
|
542
544
|
offset ||= offset_index
|
543
545
|
@offsets[offset + index] ||= find_nth_with_limit_and_offset(index, 1, offset: offset).first
|
@@ -563,7 +565,7 @@ module ActiveRecord
|
|
563
565
|
|
564
566
|
def find_nth_from_last(index)
|
565
567
|
if loaded?
|
566
|
-
|
568
|
+
records[-index]
|
567
569
|
else
|
568
570
|
relation = if order_values.empty? && primary_key
|
569
571
|
order(arel_attribute(primary_key).asc)
|
@@ -584,7 +586,7 @@ module ActiveRecord
|
|
584
586
|
|
585
587
|
def find_nth_with_limit_and_offset(index, limit, offset:) # :nodoc:
|
586
588
|
if loaded?
|
587
|
-
|
589
|
+
records[index, limit]
|
588
590
|
else
|
589
591
|
index += offset
|
590
592
|
find_nth_with_limit(index, limit)
|
@@ -1141,9 +1141,9 @@ module ActiveRecord
|
|
1141
1141
|
end
|
1142
1142
|
|
1143
1143
|
def does_not_support_reverse?(order)
|
1144
|
-
#
|
1145
|
-
order
|
1146
|
-
#
|
1144
|
+
# Uses SQL function with multiple arguments.
|
1145
|
+
(order.include?(',') && order.split(',').find { |section| section.count('(') != section.count(')')}) ||
|
1146
|
+
# Uses "nulls first" like construction.
|
1147
1147
|
order =~ /nulls (first|last)\Z/i
|
1148
1148
|
end
|
1149
1149
|
|
@@ -347,7 +347,7 @@ module ActiveRecord
|
|
347
347
|
# Please check unscoped if you want to remove all previous scopes (including
|
348
348
|
# the default_scope) during the execution of a block.
|
349
349
|
def scoping
|
350
|
-
previous, klass.current_scope = klass.current_scope, self
|
350
|
+
previous, klass.current_scope = klass.current_scope(true), self
|
351
351
|
yield
|
352
352
|
ensure
|
353
353
|
klass.current_scope = previous
|
@@ -372,6 +372,9 @@ module ActiveRecord
|
|
372
372
|
#
|
373
373
|
# # Update all books that match conditions, but limit it to 5 ordered by date
|
374
374
|
# Book.where('title LIKE ?', '%Rails%').order(:created_at).limit(5).update_all(author: 'David')
|
375
|
+
#
|
376
|
+
# # Update all invoices and set the number column to its id value.
|
377
|
+
# Invoice.update_all('number = id')
|
375
378
|
def update_all(updates)
|
376
379
|
raise ArgumentError, "Empty list of attributes to change" if updates.blank?
|
377
380
|
|
@@ -576,8 +579,8 @@ module ActiveRecord
|
|
576
579
|
# return value is the relation itself, not the records.
|
577
580
|
#
|
578
581
|
# Post.where(published: true).load # => #<ActiveRecord::Relation>
|
579
|
-
def load
|
580
|
-
exec_queries unless loaded?
|
582
|
+
def load(&block)
|
583
|
+
exec_queries(&block) unless loaded?
|
581
584
|
|
582
585
|
self
|
583
586
|
end
|
@@ -686,6 +689,10 @@ module ActiveRecord
|
|
686
689
|
"#<#{self.class.name} [#{entries.join(', ')}]>"
|
687
690
|
end
|
688
691
|
|
692
|
+
def empty_scope? # :nodoc:
|
693
|
+
@values == klass.unscoped.values
|
694
|
+
end
|
695
|
+
|
689
696
|
protected
|
690
697
|
|
691
698
|
def load_records(records)
|
@@ -695,8 +702,8 @@ module ActiveRecord
|
|
695
702
|
|
696
703
|
private
|
697
704
|
|
698
|
-
def exec_queries
|
699
|
-
@records = eager_loading? ? find_with_associations.freeze : @klass.find_by_sql(arel, bound_attributes).freeze
|
705
|
+
def exec_queries(&block)
|
706
|
+
@records = eager_loading? ? find_with_associations.freeze : @klass.find_by_sql(arel, bound_attributes, &block).freeze
|
700
707
|
|
701
708
|
preload = preload_values
|
702
709
|
preload += includes_values unless eager_loading?
|
data/lib/active_record/result.rb
CHANGED
@@ -75,8 +75,14 @@ module ActiveRecord
|
|
75
75
|
hash_rows[idx]
|
76
76
|
end
|
77
77
|
|
78
|
+
def first
|
79
|
+
return nil if @rows.empty?
|
80
|
+
Hash[@columns.zip(@rows.first)]
|
81
|
+
end
|
82
|
+
|
78
83
|
def last
|
79
|
-
|
84
|
+
return nil if @rows.empty?
|
85
|
+
Hash[@columns.zip(@rows.last)]
|
80
86
|
end
|
81
87
|
|
82
88
|
def cast_values(type_overrides = {}) # :nodoc:
|
@@ -116,7 +116,17 @@ module ActiveRecord
|
|
116
116
|
def sanitize_sql_hash_for_assignment(attrs, table)
|
117
117
|
c = connection
|
118
118
|
attrs.map do |attr, value|
|
119
|
-
value
|
119
|
+
if value.is_a?(Base)
|
120
|
+
require "active_support/core_ext/string/filters"
|
121
|
+
ActiveSupport::Deprecation.warn(<<-WARNING.squish)
|
122
|
+
Passing `ActiveRecord::Base` objects to
|
123
|
+
`sanitize_sql_hash_for_assignment` (or methods which call it,
|
124
|
+
such as `update_all`) is deprecated. Please pass the id directly,
|
125
|
+
instead.
|
126
|
+
WARNING
|
127
|
+
else
|
128
|
+
value = type_for_attribute(attr.to_s).serialize(value)
|
129
|
+
end
|
120
130
|
"#{c.quote_table_name_for_assignment(table, attr)} = #{c.quote(value)}"
|
121
131
|
end.join(', ')
|
122
132
|
end
|
@@ -105,12 +105,7 @@ HEADER
|
|
105
105
|
tbl = StringIO.new
|
106
106
|
|
107
107
|
# first dump primary key column
|
108
|
-
|
109
|
-
pk = @connection.primary_keys(table)
|
110
|
-
pk = pk.first unless pk.size > 1
|
111
|
-
else
|
112
|
-
pk = @connection.primary_key(table)
|
113
|
-
end
|
108
|
+
pk = @connection.primary_key(table)
|
114
109
|
|
115
110
|
tbl.print " create_table #{remove_prefix_and_suffix(table).inspect}"
|
116
111
|
|
@@ -132,10 +127,8 @@ HEADER
|
|
132
127
|
tbl.print ", force: :cascade"
|
133
128
|
|
134
129
|
table_options = @connection.table_options(table)
|
135
|
-
|
136
|
-
|
137
|
-
if comment = @connection.table_comment(table).presence
|
138
|
-
tbl.print ", comment: #{comment.inspect}"
|
130
|
+
if table_options.present?
|
131
|
+
tbl.print ", #{format_options(table_options)}"
|
139
132
|
end
|
140
133
|
|
141
134
|
tbl.puts " do |t|"
|
@@ -218,13 +211,9 @@ HEADER
|
|
218
211
|
index.columns.inspect,
|
219
212
|
"name: #{index.name.inspect}",
|
220
213
|
]
|
221
|
-
index_parts <<
|
222
|
-
|
223
|
-
|
224
|
-
index_parts << "length: #{Hash[index.columns.zip(index.lengths)].inspect}" if index_lengths.any?
|
225
|
-
|
226
|
-
index_orders = index.orders || {}
|
227
|
-
index_parts << "order: #{index.orders.inspect}" if index_orders.any?
|
214
|
+
index_parts << "unique: true" if index.unique
|
215
|
+
index_parts << "length: { #{format_options(index.lengths)} }" if index.lengths.present?
|
216
|
+
index_parts << "order: { #{format_options(index.orders)} }" if index.orders.present?
|
228
217
|
index_parts << "where: #{index.where.inspect}" if index.where
|
229
218
|
index_parts << "using: #{index.using.inspect}" if index.using
|
230
219
|
index_parts << "type: #{index.type.inspect}" if index.type
|
@@ -262,6 +251,10 @@ HEADER
|
|
262
251
|
end
|
263
252
|
end
|
264
253
|
|
254
|
+
def format_options(options)
|
255
|
+
options.map { |key, value| "#{key}: #{value.inspect}" }.join(", ")
|
256
|
+
end
|
257
|
+
|
265
258
|
def remove_prefix_and_suffix(table)
|
266
259
|
table.gsub(/^(#{@options[:table_name_prefix]})(.+)(#{@options[:table_name_suffix]})$/, "\\2")
|
267
260
|
end
|
@@ -110,7 +110,11 @@ module ActiveRecord
|
|
110
110
|
|
111
111
|
if self.default_scope_override
|
112
112
|
# The user has defined their own default scope method, so call that
|
113
|
-
evaluate_default_scope
|
113
|
+
evaluate_default_scope do
|
114
|
+
if scope = default_scope
|
115
|
+
(base_rel ||= relation).merge(scope)
|
116
|
+
end
|
117
|
+
end
|
114
118
|
elsif default_scopes.any?
|
115
119
|
base_rel ||= relation
|
116
120
|
evaluate_default_scope do
|
@@ -29,13 +29,25 @@ module ActiveRecord
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
-
def
|
33
|
-
|
32
|
+
def scope_for_association(scope = relation) # :nodoc:
|
33
|
+
current_scope = self.current_scope
|
34
34
|
|
35
|
-
if
|
36
|
-
|
35
|
+
if current_scope && current_scope.empty_scope?
|
36
|
+
scope
|
37
37
|
else
|
38
|
-
|
38
|
+
default_scoped(scope)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def default_scoped(scope = relation) # :nodoc:
|
43
|
+
build_default_scope(scope) || scope
|
44
|
+
end
|
45
|
+
|
46
|
+
def default_extensions # :nodoc:
|
47
|
+
if scope = current_scope || build_default_scope
|
48
|
+
scope.extensions
|
49
|
+
else
|
50
|
+
[]
|
39
51
|
end
|
40
52
|
end
|
41
53
|
|
@@ -174,7 +186,7 @@ module ActiveRecord
|
|
174
186
|
protected
|
175
187
|
|
176
188
|
def valid_scope_name?(name)
|
177
|
-
if respond_to?(name, true)
|
189
|
+
if respond_to?(name, true) && logger
|
178
190
|
logger.warn "Creating scope :#{name}. " \
|
179
191
|
"Overwriting existing method #{self.name}.#{name}."
|
180
192
|
end
|
@@ -10,8 +10,8 @@ module ActiveRecord
|
|
10
10
|
end
|
11
11
|
|
12
12
|
module ClassMethods
|
13
|
-
def current_scope
|
14
|
-
ScopeRegistry.value_for(:current_scope, self)
|
13
|
+
def current_scope(skip_inherited_scope = false) # :nodoc:
|
14
|
+
ScopeRegistry.value_for(:current_scope, self, skip_inherited_scope)
|
15
15
|
end
|
16
16
|
|
17
17
|
def current_scope=(scope) #:nodoc:
|
@@ -75,8 +75,9 @@ module ActiveRecord
|
|
75
75
|
end
|
76
76
|
|
77
77
|
# Obtains the value for a given +scope_type+ and +model+.
|
78
|
-
def value_for(scope_type, model)
|
78
|
+
def value_for(scope_type, model, skip_inherited_scope = false)
|
79
79
|
raise_invalid_scope_type!(scope_type)
|
80
|
+
return @registry[scope_type][model.name] if skip_inherited_scope
|
80
81
|
klass = model
|
81
82
|
base = model.base_class
|
82
83
|
while klass <= base
|
@@ -9,7 +9,7 @@ module ActiveRecord #:nodoc:
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def serializable_hash(options = nil)
|
12
|
-
options = options.try(:
|
12
|
+
options = options.try(:dup) || {}
|
13
13
|
|
14
14
|
options[:except] = Array(options[:except]).map(&:to_s)
|
15
15
|
options[:except] |= Array(self.class.inheritance_column)
|
@@ -101,12 +101,12 @@ module ActiveRecord
|
|
101
101
|
@bind_map = bind_map
|
102
102
|
end
|
103
103
|
|
104
|
-
def execute(params, klass, connection)
|
104
|
+
def execute(params, klass, connection, &block)
|
105
105
|
bind_values = bind_map.bind params
|
106
106
|
|
107
107
|
sql = query_builder.sql_for bind_values, connection
|
108
108
|
|
109
|
-
klass.find_by_sql(sql, bind_values, preparable: true)
|
109
|
+
klass.find_by_sql(sql, bind_values, preparable: true, &block)
|
110
110
|
end
|
111
111
|
alias :call :execute
|
112
112
|
end
|
@@ -42,10 +42,11 @@ module ActiveRecord
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def associated_table(table_name)
|
45
|
-
|
45
|
+
association = klass._reflect_on_association(table_name) || klass._reflect_on_association(table_name.to_s.singularize)
|
46
46
|
|
47
|
-
association
|
48
|
-
|
47
|
+
if !association && table_name == arel_table.name
|
48
|
+
return self
|
49
|
+
elsif association && !association.polymorphic?
|
49
50
|
association_klass = association.klass
|
50
51
|
arel_table = association_klass.arel_table.alias(table_name)
|
51
52
|
else
|
@@ -154,6 +154,8 @@ module ActiveRecord
|
|
154
154
|
end
|
155
155
|
|
156
156
|
def migrate
|
157
|
+
raise "Empty VERSION provided" if ENV["VERSION"] && ENV["VERSION"].empty?
|
158
|
+
|
157
159
|
verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
|
158
160
|
version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
|
159
161
|
scope = ENV['SCOPE']
|
@@ -213,22 +215,22 @@ module ActiveRecord
|
|
213
215
|
class_for_adapter(configuration['adapter']).new(*arguments).structure_load(filename)
|
214
216
|
end
|
215
217
|
|
216
|
-
def load_schema(configuration, format = ActiveRecord::Base.schema_format, file = nil) # :nodoc:
|
218
|
+
def load_schema(configuration, format = ActiveRecord::Base.schema_format, file = nil, environment = env) # :nodoc:
|
217
219
|
file ||= schema_file(format)
|
218
220
|
|
221
|
+
check_schema_file(file)
|
222
|
+
ActiveRecord::Base.establish_connection(configuration)
|
223
|
+
|
219
224
|
case format
|
220
225
|
when :ruby
|
221
|
-
check_schema_file(file)
|
222
|
-
ActiveRecord::Base.establish_connection(configuration)
|
223
226
|
load(file)
|
224
227
|
when :sql
|
225
|
-
check_schema_file(file)
|
226
228
|
structure_load(configuration, file)
|
227
229
|
else
|
228
230
|
raise ArgumentError, "unknown format #{format.inspect}"
|
229
231
|
end
|
230
232
|
ActiveRecord::InternalMetadata.create_table
|
231
|
-
ActiveRecord::InternalMetadata[:environment] =
|
233
|
+
ActiveRecord::InternalMetadata[:environment] = environment
|
232
234
|
end
|
233
235
|
|
234
236
|
def load_schema_for(*args)
|
@@ -249,8 +251,8 @@ module ActiveRecord
|
|
249
251
|
end
|
250
252
|
|
251
253
|
def load_schema_current(format = ActiveRecord::Base.schema_format, file = nil, environment = env)
|
252
|
-
each_current_configuration(environment) { |configuration|
|
253
|
-
load_schema configuration, format, file
|
254
|
+
each_current_configuration(environment) { |configuration, configuration_environment|
|
255
|
+
load_schema configuration, format, file, configuration_environment
|
254
256
|
}
|
255
257
|
ActiveRecord::Base.establish_connection(environment.to_sym)
|
256
258
|
end
|
@@ -258,7 +260,7 @@ module ActiveRecord
|
|
258
260
|
def check_schema_file(filename)
|
259
261
|
unless File.exist?(filename)
|
260
262
|
message = %{#{filename} doesn't exist yet. Run `rails db:migrate` to create it, then try again.}
|
261
|
-
message << %{ If you do not intend to use a database, you should instead alter #{Rails.root}/config/application.rb to limit the frameworks that will be loaded.} if defined?(::Rails)
|
263
|
+
message << %{ If you do not intend to use a database, you should instead alter #{Rails.root}/config/application.rb to limit the frameworks that will be loaded.} if defined?(::Rails.root)
|
262
264
|
Kernel.abort message
|
263
265
|
end
|
264
266
|
end
|
@@ -287,9 +289,10 @@ module ActiveRecord
|
|
287
289
|
environments = [environment]
|
288
290
|
environments << 'test' if environment == 'development'
|
289
291
|
|
290
|
-
|
291
|
-
|
292
|
-
|
292
|
+
ActiveRecord::Base.configurations.slice(*environments).each do |configuration_environment, configuration|
|
293
|
+
next unless configuration["database"]
|
294
|
+
|
295
|
+
yield configuration, configuration_environment
|
293
296
|
end
|
294
297
|
end
|
295
298
|
|
@@ -16,7 +16,7 @@ module ActiveRecord
|
|
16
16
|
configuration.merge('encoding' => encoding)
|
17
17
|
establish_connection configuration
|
18
18
|
rescue ActiveRecord::StatementInvalid => error
|
19
|
-
if
|
19
|
+
if error.cause.is_a?(PG::DuplicateDatabase)
|
20
20
|
raise DatabaseAlreadyExists
|
21
21
|
else
|
22
22
|
raise
|
@@ -8,7 +8,12 @@ module ActiveRecord
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def touch_later(*names) # :nodoc:
|
11
|
-
|
11
|
+
unless persisted?
|
12
|
+
raise ActiveRecordError, <<-MSG.squish
|
13
|
+
cannot touch on a new or destroyed record object. Consider using
|
14
|
+
persisted?, new_record?, or destroyed? before touching
|
15
|
+
MSG
|
16
|
+
end
|
12
17
|
|
13
18
|
@_defer_touch_attrs ||= timestamp_attributes_for_update_in_model
|
14
19
|
@_defer_touch_attrs |= names
|
@@ -124,7 +124,7 @@ module ActiveRecord
|
|
124
124
|
# # statement will cause a PostgreSQL error, even though the unique
|
125
125
|
# # constraint is no longer violated:
|
126
126
|
# Number.create(i: 1)
|
127
|
-
# # => "
|
127
|
+
# # => "PG::Error: ERROR: current transaction is aborted, commands
|
128
128
|
# # ignored until end of transaction block"
|
129
129
|
# end
|
130
130
|
#
|
@@ -86,11 +86,10 @@ module ActiveRecord
|
|
86
86
|
|
87
87
|
def scope_relation(record, table, relation)
|
88
88
|
Array(options[:scope]).each do |scope_item|
|
89
|
-
|
90
|
-
|
91
|
-
scope_item = reflection.foreign_key
|
89
|
+
scope_value = if record.class._reflect_on_association(scope_item)
|
90
|
+
record.association(scope_item).reader
|
92
91
|
else
|
93
|
-
|
92
|
+
record._read_attribute(scope_item)
|
94
93
|
end
|
95
94
|
relation = relation.where(scope_item => scope_value)
|
96
95
|
end
|