activerecord 4.2.0.beta1 → 4.2.0.beta2
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 +137 -38
- data/lib/active_record/associations.rb +78 -13
- data/lib/active_record/associations/association_scope.rb +53 -40
- data/lib/active_record/associations/collection_association.rb +1 -1
- data/lib/active_record/associations/collection_proxy.rb +4 -4
- data/lib/active_record/associations/has_many_through_association.rb +6 -6
- data/lib/active_record/associations/join_dependency/join_association.rb +1 -1
- data/lib/active_record/associations/preloader.rb +32 -23
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations/through_association.rb +5 -1
- data/lib/active_record/attribute_methods.rb +7 -7
- data/lib/active_record/attribute_methods/dirty.rb +20 -9
- data/lib/active_record/attribute_methods/query.rb +1 -1
- data/lib/active_record/attribute_methods/read.rb +1 -3
- data/lib/active_record/attribute_methods/serialization.rb +3 -4
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +2 -0
- data/lib/active_record/autosave_association.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +5 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +5 -8
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +8 -4
- data/lib/active_record/connection_adapters/abstract/transaction.rb +11 -5
- data/lib/active_record/connection_adapters/abstract_adapter.rb +7 -1
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +23 -15
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -1
- data/lib/active_record/connection_adapters/mysql_adapter.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +3 -5
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +8 -6
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +9 -6
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +6 -5
- data/lib/active_record/core.rb +11 -3
- data/lib/active_record/counter_cache.rb +1 -1
- data/lib/active_record/fixtures.rb +15 -8
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/migration.rb +8 -12
- data/lib/active_record/reflection.rb +20 -18
- data/lib/active_record/relation/calculations.rb +7 -7
- data/lib/active_record/relation/finder_methods.rb +10 -9
- data/lib/active_record/relation/predicate_builder.rb +2 -2
- data/lib/active_record/relation/predicate_builder/array_handler.rb +12 -4
- data/lib/active_record/relation/query_methods.rb +8 -12
- data/lib/active_record/schema_dumper.rb +20 -28
- data/lib/active_record/tasks/database_tasks.rb +9 -5
- data/lib/active_record/transactions.rb +9 -9
- data/lib/active_record/type.rb +1 -0
- data/lib/active_record/type/binary.rb +10 -0
- data/lib/active_record/type/decorator.rb +14 -0
- data/lib/active_record/type/serialized.rb +8 -3
- metadata +7 -6
@@ -83,6 +83,11 @@ module ActiveRecord
|
|
83
83
|
exec_query(sql, name, binds)
|
84
84
|
end
|
85
85
|
|
86
|
+
# Executes the truncate statement.
|
87
|
+
def truncate(table_name, name = nil)
|
88
|
+
raise NotImplementedError
|
89
|
+
end
|
90
|
+
|
86
91
|
# Executes update +sql+ statement in the context of this connection using
|
87
92
|
# +binds+ as the bind substitutes. +name+ is logged along with
|
88
93
|
# the executed +sql+ statement.
|
@@ -2,7 +2,6 @@ require 'date'
|
|
2
2
|
require 'set'
|
3
3
|
require 'bigdecimal'
|
4
4
|
require 'bigdecimal/util'
|
5
|
-
require 'active_support/core_ext/string/strip'
|
6
5
|
|
7
6
|
module ActiveRecord
|
8
7
|
module ConnectionAdapters #:nodoc:
|
@@ -61,12 +60,11 @@ module ActiveRecord
|
|
61
60
|
def emit_warning_if_null_unspecified(options)
|
62
61
|
return if options.key?(:null)
|
63
62
|
|
64
|
-
ActiveSupport::Deprecation.warn
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
MESSAGE
|
63
|
+
ActiveSupport::Deprecation.warn \
|
64
|
+
"`timestamp` was called without specifying an option for `null`. In Rails " \
|
65
|
+
"5.0, this behavior will change to `null: false`. You should manually " \
|
66
|
+
"specify `null: true` to prevent the behavior of your existing migrations " \
|
67
|
+
"from changing."
|
70
68
|
end
|
71
69
|
end
|
72
70
|
|
@@ -327,7 +325,6 @@ module ActiveRecord
|
|
327
325
|
end
|
328
326
|
|
329
327
|
column.limit = limit
|
330
|
-
column.array = options[:array] if column.respond_to?(:array)
|
331
328
|
column.precision = options[:precision]
|
332
329
|
column.scale = options[:scale]
|
333
330
|
column.default = options[:default]
|
@@ -19,12 +19,16 @@ module ActiveRecord
|
|
19
19
|
spec = {}
|
20
20
|
spec[:name] = column.name.inspect
|
21
21
|
spec[:type] = column.type.to_s
|
22
|
-
spec[:
|
22
|
+
spec[:null] = 'false' unless column.null
|
23
|
+
|
24
|
+
limit = column.limit || types[column.type][:limit]
|
25
|
+
spec[:limit] = limit.inspect if limit
|
23
26
|
spec[:precision] = column.precision.inspect if column.precision
|
24
27
|
spec[:scale] = column.scale.inspect if column.scale
|
25
|
-
|
26
|
-
|
27
|
-
spec
|
28
|
+
|
29
|
+
default = schema_default(column) if column.has_default?
|
30
|
+
spec[:default] = default unless default.nil?
|
31
|
+
|
28
32
|
spec
|
29
33
|
end
|
30
34
|
|
@@ -190,11 +190,17 @@ module ActiveRecord
|
|
190
190
|
rollback_transaction if transaction
|
191
191
|
raise
|
192
192
|
ensure
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
193
|
+
unless error
|
194
|
+
if Thread.current.status == 'aborting'
|
195
|
+
rollback_transaction
|
196
|
+
else
|
197
|
+
begin
|
198
|
+
commit_transaction
|
199
|
+
rescue Exception
|
200
|
+
transaction.rollback unless transaction.state.completed?
|
201
|
+
raise
|
202
|
+
end
|
203
|
+
end
|
198
204
|
end
|
199
205
|
end
|
200
206
|
|
@@ -66,6 +66,7 @@ module ActiveRecord
|
|
66
66
|
# Most of the methods in the adapter are useful during migrations. Most
|
67
67
|
# notably, the instance methods provided by SchemaStatement are very useful.
|
68
68
|
class AbstractAdapter
|
69
|
+
ADAPTER_NAME = 'Abstract'.freeze
|
69
70
|
include Quoting, DatabaseStatements, SchemaStatements
|
70
71
|
include DatabaseLimits
|
71
72
|
include QueryCache
|
@@ -167,7 +168,7 @@ module ActiveRecord
|
|
167
168
|
# Returns the human-readable name of the adapter. Use mixed case - one
|
168
169
|
# can always use downcase if needed.
|
169
170
|
def adapter_name
|
170
|
-
|
171
|
+
self.class::ADAPTER_NAME
|
171
172
|
end
|
172
173
|
|
173
174
|
# Does this adapter support migrations?
|
@@ -239,6 +240,11 @@ module ActiveRecord
|
|
239
240
|
false
|
240
241
|
end
|
241
242
|
|
243
|
+
# Does this adapter support views?
|
244
|
+
def supports_views?
|
245
|
+
false
|
246
|
+
end
|
247
|
+
|
242
248
|
# This is meant to be implemented by the adapters that support extensions
|
243
249
|
def disable_extension(name)
|
244
250
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'arel/visitors/bind_visitor'
|
2
|
+
require 'active_support/core_ext/string/strip'
|
2
3
|
|
3
4
|
module ActiveRecord
|
4
5
|
module ConnectionAdapters
|
@@ -161,10 +162,6 @@ module ActiveRecord
|
|
161
162
|
end
|
162
163
|
end
|
163
164
|
|
164
|
-
def adapter_name #:nodoc:
|
165
|
-
self.class::ADAPTER_NAME
|
166
|
-
end
|
167
|
-
|
168
165
|
# Returns true, since this connection adapter supports migrations.
|
169
166
|
def supports_migrations?
|
170
167
|
true
|
@@ -200,6 +197,10 @@ module ActiveRecord
|
|
200
197
|
true
|
201
198
|
end
|
202
199
|
|
200
|
+
def supports_views?
|
201
|
+
version[0] >= 5
|
202
|
+
end
|
203
|
+
|
203
204
|
def native_database_types
|
204
205
|
NATIVE_DATABASE_TYPES
|
205
206
|
end
|
@@ -388,6 +389,10 @@ module ActiveRecord
|
|
388
389
|
end
|
389
390
|
end
|
390
391
|
|
392
|
+
def truncate(table_name, name = nil)
|
393
|
+
execute "TRUNCATE TABLE #{quote_table_name(table_name)}", name
|
394
|
+
end
|
395
|
+
|
391
396
|
def table_exists?(name)
|
392
397
|
return false unless name.present?
|
393
398
|
return true if tables(nil, nil, name).any?
|
@@ -639,18 +644,21 @@ module ActiveRecord
|
|
639
644
|
|
640
645
|
def initialize_type_map(m) # :nodoc:
|
641
646
|
super
|
647
|
+
|
642
648
|
m.register_type(%r(enum)i) do |sql_type|
|
643
649
|
limit = sql_type[/^enum\((.+)\)/i, 1]
|
644
650
|
.split(',').map{|enum| enum.strip.length - 2}.max
|
645
651
|
Type::String.new(limit: limit)
|
646
652
|
end
|
647
653
|
|
648
|
-
m.register_type %r(tinytext)i, Type::Text.new(limit:
|
649
|
-
m.register_type %r(tinyblob)i, Type::Binary.new(limit:
|
650
|
-
m.register_type %r(
|
651
|
-
m.register_type %r(
|
652
|
-
m.register_type %r(
|
653
|
-
m.register_type %r(
|
654
|
+
m.register_type %r(tinytext)i, Type::Text.new(limit: 2**8 - 1)
|
655
|
+
m.register_type %r(tinyblob)i, Type::Binary.new(limit: 2**8 - 1)
|
656
|
+
m.register_type %r(text)i, Type::Text.new(limit: 2**16 - 1)
|
657
|
+
m.register_type %r(blob)i, Type::Binary.new(limit: 2**16 - 1)
|
658
|
+
m.register_type %r(mediumtext)i, Type::Text.new(limit: 2**24 - 1)
|
659
|
+
m.register_type %r(mediumblob)i, Type::Binary.new(limit: 2**24 - 1)
|
660
|
+
m.register_type %r(longtext)i, Type::Text.new(limit: 2**32 - 1)
|
661
|
+
m.register_type %r(longblob)i, Type::Binary.new(limit: 2**32 - 1)
|
654
662
|
m.register_type %r(^bigint)i, Type::Integer.new(limit: 8)
|
655
663
|
m.register_type %r(^int)i, Type::Integer.new(limit: 4)
|
656
664
|
m.register_type %r(^mediumint)i, Type::Integer.new(limit: 3)
|
@@ -782,10 +790,6 @@ module ActiveRecord
|
|
782
790
|
full_version =~ /mariadb/i
|
783
791
|
end
|
784
792
|
|
785
|
-
def supports_views?
|
786
|
-
version[0] >= 5
|
787
|
-
end
|
788
|
-
|
789
793
|
def supports_rename_index?
|
790
794
|
mariadb? ? false : (version[0] == 5 && version[1] >= 7) || version[0] >= 6
|
791
795
|
end
|
@@ -812,7 +816,11 @@ module ActiveRecord
|
|
812
816
|
# NAMES does not have an equals sign, see
|
813
817
|
# http://dev.mysql.com/doc/refman/5.0/en/set-statement.html#id944430
|
814
818
|
# (trailing comma because variable_assignments will always have content)
|
815
|
-
|
819
|
+
if @config[:encoding]
|
820
|
+
encoding = "NAMES #{@config[:encoding]}"
|
821
|
+
encoding << " COLLATE #{@config[:collation]}" if @config[:collation]
|
822
|
+
encoding << ", "
|
823
|
+
end
|
816
824
|
|
817
825
|
# Gather up all of the SET variables...
|
818
826
|
variable_assignments = variables.map do |k, v|
|
@@ -66,7 +66,7 @@ module ActiveRecord
|
|
66
66
|
# * <tt>:sslcipher</tt> - Necessary to use MySQL with an SSL connection.
|
67
67
|
#
|
68
68
|
class MysqlAdapter < AbstractMysqlAdapter
|
69
|
-
ADAPTER_NAME = 'MySQL'
|
69
|
+
ADAPTER_NAME = 'MySQL'.freeze
|
70
70
|
|
71
71
|
class StatementPool < ConnectionAdapters::StatementPool
|
72
72
|
def initialize(connection, max = 1000)
|
@@ -25,10 +25,10 @@ module ActiveRecord
|
|
25
25
|
if !infinity?(from) && extracted[:exclude_start]
|
26
26
|
if from.respond_to?(:succ)
|
27
27
|
from = from.succ
|
28
|
-
ActiveSupport::Deprecation.warn
|
29
|
-
Excluding the beginning of a Range is only partialy supported
|
30
|
-
This is not reliable and will be removed in
|
31
|
-
|
28
|
+
ActiveSupport::Deprecation.warn \
|
29
|
+
"Excluding the beginning of a Range is only partialy supported " \
|
30
|
+
"through `#succ`. This is not reliable and will be removed in " \
|
31
|
+
"the future."
|
32
32
|
else
|
33
33
|
raise ArgumentError, "The Ruby Range object does not support excluding the beginning of a Range. (unsupported value: '#{value}')"
|
34
34
|
end
|
@@ -131,12 +131,10 @@ module ActiveRecord
|
|
131
131
|
column name, type, options
|
132
132
|
end
|
133
133
|
|
134
|
-
def
|
135
|
-
super
|
136
|
-
column = self[name]
|
134
|
+
def new_column_definition(name, type, options) # :nodoc:
|
135
|
+
column = super
|
137
136
|
column.array = options[:array]
|
138
|
-
|
139
|
-
self
|
137
|
+
column
|
140
138
|
end
|
141
139
|
|
142
140
|
private
|
@@ -60,8 +60,8 @@ module ActiveRecord
|
|
60
60
|
def create_database(name, options = {})
|
61
61
|
options = { encoding: 'utf8' }.merge!(options.symbolize_keys)
|
62
62
|
|
63
|
-
option_string = options.
|
64
|
-
case key
|
63
|
+
option_string = options.inject("") do |memo, (key, value)|
|
64
|
+
memo += case key
|
65
65
|
when :owner
|
66
66
|
" OWNER = \"#{value}\""
|
67
67
|
when :template
|
@@ -281,9 +281,9 @@ module ActiveRecord
|
|
281
281
|
def default_sequence_name(table_name, pk = nil) #:nodoc:
|
282
282
|
result = serial_sequence(table_name, pk || 'id')
|
283
283
|
return nil unless result
|
284
|
-
Utils.extract_schema_qualified_name(result)
|
284
|
+
Utils.extract_schema_qualified_name(result).to_s
|
285
285
|
rescue ActiveRecord::StatementInvalid
|
286
|
-
PostgreSQL::Name.new(nil, "#{table_name}_#{pk || 'id'}_seq")
|
286
|
+
PostgreSQL::Name.new(nil, "#{table_name}_#{pk || 'id'}_seq").to_s
|
287
287
|
end
|
288
288
|
|
289
289
|
def serial_sequence(table, column)
|
@@ -466,7 +466,7 @@ module ActiveRecord
|
|
466
466
|
|
467
467
|
def foreign_keys(table_name)
|
468
468
|
fk_info = select_all <<-SQL.strip_heredoc
|
469
|
-
SELECT t2.
|
469
|
+
SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete
|
470
470
|
FROM pg_constraint c
|
471
471
|
JOIN pg_class t1 ON c.conrelid = t1.oid
|
472
472
|
JOIN pg_class t2 ON c.confrelid = t2.oid
|
@@ -488,6 +488,7 @@ module ActiveRecord
|
|
488
488
|
|
489
489
|
options[:on_delete] = extract_foreign_key_action(row['on_delete'])
|
490
490
|
options[:on_update] = extract_foreign_key_action(row['on_update'])
|
491
|
+
|
491
492
|
ForeignKeyDefinition.new(table_name, row['to_table'], options)
|
492
493
|
end
|
493
494
|
end
|
@@ -549,7 +550,8 @@ module ActiveRecord
|
|
549
550
|
# Convert Arel node to string
|
550
551
|
s = s.to_sql unless s.is_a?(String)
|
551
552
|
# Remove any ASC/DESC modifiers
|
552
|
-
s.gsub(/\s+(?:ASC|DESC)
|
553
|
+
s.gsub(/\s+(?:ASC|DESC)\b/i, '')
|
554
|
+
.gsub(/\s+NULLS\s+(?:FIRST|LAST)\b/i, '')
|
553
555
|
}.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" }
|
554
556
|
|
555
557
|
[super, *order_columns].join(', ')
|
@@ -74,7 +74,7 @@ module ActiveRecord
|
|
74
74
|
# In addition, default connection parameters of libpq can be set per environment variables.
|
75
75
|
# See http://www.postgresql.org/docs/9.1/static/libpq-envars.html .
|
76
76
|
class PostgreSQLAdapter < AbstractAdapter
|
77
|
-
ADAPTER_NAME = 'PostgreSQL'
|
77
|
+
ADAPTER_NAME = 'PostgreSQL'.freeze
|
78
78
|
|
79
79
|
NATIVE_DATABASE_TYPES = {
|
80
80
|
primary_key: "serial primary key",
|
@@ -118,11 +118,6 @@ module ActiveRecord
|
|
118
118
|
include PostgreSQL::DatabaseStatements
|
119
119
|
include Savepoints
|
120
120
|
|
121
|
-
# Returns 'PostgreSQL' as adapter name for identification purposes.
|
122
|
-
def adapter_name
|
123
|
-
ADAPTER_NAME
|
124
|
-
end
|
125
|
-
|
126
121
|
def schema_creation # :nodoc:
|
127
122
|
PostgreSQL::SchemaCreation.new self
|
128
123
|
end
|
@@ -163,6 +158,10 @@ module ActiveRecord
|
|
163
158
|
true
|
164
159
|
end
|
165
160
|
|
161
|
+
def supports_views?
|
162
|
+
true
|
163
|
+
end
|
164
|
+
|
166
165
|
def index_algorithms
|
167
166
|
{ concurrently: 'CONCURRENTLY' }
|
168
167
|
end
|
@@ -256,6 +255,10 @@ module ActiveRecord
|
|
256
255
|
@statements.clear
|
257
256
|
end
|
258
257
|
|
258
|
+
def truncate(table_name, name = nil)
|
259
|
+
exec_query "TRUNCATE TABLE #{quote_table_name(table_name)}", name, []
|
260
|
+
end
|
261
|
+
|
259
262
|
# Is this connection alive and ready for queries?
|
260
263
|
def active?
|
261
264
|
@connection.query 'SELECT 1'
|
@@ -67,6 +67,7 @@ module ActiveRecord
|
|
67
67
|
#
|
68
68
|
# * <tt>:database</tt> - Path to the database file.
|
69
69
|
class SQLite3Adapter < AbstractAdapter
|
70
|
+
ADAPTER_NAME = 'SQLite'.freeze
|
70
71
|
include Savepoints
|
71
72
|
|
72
73
|
NATIVE_DATABASE_TYPES = {
|
@@ -147,10 +148,6 @@ module ActiveRecord
|
|
147
148
|
end
|
148
149
|
end
|
149
150
|
|
150
|
-
def adapter_name #:nodoc:
|
151
|
-
'SQLite'
|
152
|
-
end
|
153
|
-
|
154
151
|
def supports_ddl_transactions?
|
155
152
|
true
|
156
153
|
end
|
@@ -186,6 +183,10 @@ module ActiveRecord
|
|
186
183
|
true
|
187
184
|
end
|
188
185
|
|
186
|
+
def supports_views?
|
187
|
+
true
|
188
|
+
end
|
189
|
+
|
189
190
|
def active?
|
190
191
|
@active != false
|
191
192
|
end
|
@@ -372,7 +373,7 @@ module ActiveRecord
|
|
372
373
|
sql = <<-SQL
|
373
374
|
SELECT name
|
374
375
|
FROM sqlite_master
|
375
|
-
WHERE type = 'table' AND NOT name = 'sqlite_sequence'
|
376
|
+
WHERE (type = 'table' OR type = 'view') AND NOT name = 'sqlite_sequence'
|
376
377
|
SQL
|
377
378
|
sql << " AND name = #{quote_table_name(table_name)}" if table_name
|
378
379
|
|
data/lib/active_record/core.rb
CHANGED
@@ -124,6 +124,8 @@ module ActiveRecord
|
|
124
124
|
def find(*ids)
|
125
125
|
# We don't have cache keys for this stuff yet
|
126
126
|
return super unless ids.length == 1
|
127
|
+
# Allow symbols to super to maintain compatibility for deprecated finders until Rails 5
|
128
|
+
return super if ids.first.kind_of?(Symbol)
|
127
129
|
return super if block_given? ||
|
128
130
|
primary_key.nil? ||
|
129
131
|
default_scopes.any? ||
|
@@ -151,7 +153,8 @@ module ActiveRecord
|
|
151
153
|
end
|
152
154
|
|
153
155
|
def find_by(*args)
|
154
|
-
return super if current_scope || args.
|
156
|
+
return super if current_scope || !(Hash === args.first) || reflect_on_all_aggregations.any?
|
157
|
+
return super if default_scopes.any?
|
155
158
|
|
156
159
|
hash = args.first
|
157
160
|
|
@@ -159,6 +162,9 @@ module ActiveRecord
|
|
159
162
|
v.nil? || Array === v || Hash === v
|
160
163
|
}
|
161
164
|
|
165
|
+
# We can't cache Post.find_by(author: david) ...yet
|
166
|
+
return super unless hash.keys.all? { |k| columns_hash.has_key?(k.to_s) }
|
167
|
+
|
162
168
|
key = hash.keys
|
163
169
|
|
164
170
|
klass = self
|
@@ -177,9 +183,11 @@ module ActiveRecord
|
|
177
183
|
end
|
178
184
|
end
|
179
185
|
|
180
|
-
def
|
181
|
-
|
186
|
+
def find_by!(*args)
|
187
|
+
find_by(*args) or raise RecordNotFound.new("Couldn't find #{name}")
|
188
|
+
end
|
182
189
|
|
190
|
+
def initialize_generated_modules
|
183
191
|
generated_association_methods
|
184
192
|
end
|
185
193
|
|