activerecord 4.2.1 → 4.2.7.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 +368 -1
- data/lib/active_record/aggregations.rb +4 -3
- data/lib/active_record/association_relation.rb +13 -0
- data/lib/active_record/associations/association.rb +15 -3
- data/lib/active_record/associations/association_scope.rb +1 -0
- data/lib/active_record/associations/belongs_to_association.rb +5 -1
- data/lib/active_record/associations/builder/association.rb +1 -1
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +8 -4
- data/lib/active_record/associations/collection_association.rb +1 -7
- data/lib/active_record/associations/collection_proxy.rb +8 -7
- data/lib/active_record/associations/has_many_association.rb +8 -1
- data/lib/active_record/associations/has_many_through_association.rb +9 -0
- data/lib/active_record/associations/join_dependency.rb +8 -2
- data/lib/active_record/associations/preloader/association.rb +5 -1
- data/lib/active_record/associations/preloader.rb +4 -4
- data/lib/active_record/associations/singular_association.rb +2 -8
- data/lib/active_record/associations/through_association.rb +0 -6
- data/lib/active_record/associations.rb +1 -1
- data/lib/active_record/attribute_assignment.rb +1 -1
- data/lib/active_record/attribute_methods/dirty.rb +7 -1
- data/lib/active_record/attribute_methods.rb +3 -7
- data/lib/active_record/attribute_set/builder.rb +21 -11
- data/lib/active_record/attribute_set.rb +4 -0
- data/lib/active_record/autosave_association.rb +1 -1
- data/lib/active_record/base.rb +4 -5
- data/lib/active_record/callbacks.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +4 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +11 -2
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +16 -24
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +49 -17
- data/lib/active_record/connection_adapters/abstract/transaction.rb +1 -5
- data/lib/active_record/connection_adapters/abstract_adapter.rb +12 -1
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +38 -5
- data/lib/active_record/connection_adapters/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +3 -3
- data/lib/active_record/connection_adapters/mysql_adapter.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +17 -5
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +15 -6
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +9 -9
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +2 -12
- data/lib/active_record/core.rb +15 -8
- data/lib/active_record/enum.rb +2 -3
- data/lib/active_record/errors.rb +6 -5
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixtures.rb +8 -6
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/legacy_yaml_adapter.rb +30 -0
- data/lib/active_record/migration.rb +7 -4
- data/lib/active_record/model_schema.rb +1 -1
- data/lib/active_record/nested_attributes.rb +12 -2
- data/lib/active_record/persistence.rb +5 -3
- data/lib/active_record/railtie.rb +1 -1
- data/lib/active_record/railties/databases.rake +10 -7
- data/lib/active_record/reflection.rb +39 -27
- data/lib/active_record/relation/calculations.rb +8 -1
- data/lib/active_record/relation/delegation.rb +1 -1
- data/lib/active_record/relation/finder_methods.rb +3 -15
- data/lib/active_record/relation/merger.rb +24 -1
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -1
- data/lib/active_record/relation/predicate_builder.rb +11 -2
- data/lib/active_record/relation/query_methods.rb +15 -18
- data/lib/active_record/relation/spawn_methods.rb +7 -3
- data/lib/active_record/relation.rb +2 -1
- data/lib/active_record/scoping/default.rb +1 -0
- data/lib/active_record/tasks/database_tasks.rb +3 -2
- data/lib/active_record/tasks/mysql_database_tasks.rb +30 -16
- data/lib/active_record/tasks/postgresql_database_tasks.rb +19 -8
- data/lib/active_record/transactions.rb +16 -4
- data/lib/active_record/type/boolean.rb +1 -0
- data/lib/active_record/type/date.rb +4 -0
- data/lib/active_record/type/decimal.rb +12 -2
- data/lib/active_record/type/hash_lookup_type_map.rb +8 -2
- data/lib/active_record/type/serialized.rb +7 -1
- data/lib/active_record/validations/uniqueness.rb +15 -5
- data/lib/active_record.rb +2 -0
- metadata +9 -7
@@ -58,6 +58,12 @@ module ActiveRecord
|
|
58
58
|
SchemaCreation.new self
|
59
59
|
end
|
60
60
|
|
61
|
+
def prepare_column_options(column, types) # :nodoc:
|
62
|
+
spec = super
|
63
|
+
spec.delete(:limit) if :boolean === column.type
|
64
|
+
spec
|
65
|
+
end
|
66
|
+
|
61
67
|
class Column < ConnectionAdapters::Column # :nodoc:
|
62
68
|
attr_reader :collation, :strict, :extra
|
63
69
|
|
@@ -197,7 +203,7 @@ module ActiveRecord
|
|
197
203
|
#
|
198
204
|
# http://bugs.mysql.com/bug.php?id=39170
|
199
205
|
def supports_transaction_isolation?
|
200
|
-
version
|
206
|
+
version >= '5.0.0'
|
201
207
|
end
|
202
208
|
|
203
209
|
def supports_indexes_in_create?
|
@@ -209,7 +215,11 @@ module ActiveRecord
|
|
209
215
|
end
|
210
216
|
|
211
217
|
def supports_views?
|
212
|
-
version
|
218
|
+
version >= '5.0.0'
|
219
|
+
end
|
220
|
+
|
221
|
+
def supports_datetime_with_precision?
|
222
|
+
version >= '5.6.4'
|
213
223
|
end
|
214
224
|
|
215
225
|
def native_database_types
|
@@ -401,6 +411,7 @@ module ActiveRecord
|
|
401
411
|
result.collect { |field| field.first }
|
402
412
|
end
|
403
413
|
end
|
414
|
+
alias data_sources tables
|
404
415
|
|
405
416
|
def truncate(table_name, name = nil)
|
406
417
|
execute "TRUNCATE TABLE #{quote_table_name(table_name)}", name
|
@@ -420,6 +431,7 @@ module ActiveRecord
|
|
420
431
|
|
421
432
|
tables(nil, schema, table).any?
|
422
433
|
end
|
434
|
+
alias data_source_exists? table_exists?
|
423
435
|
|
424
436
|
# Returns an array of indexes for the given table.
|
425
437
|
def indexes(table_name, name = nil) #:nodoc:
|
@@ -598,8 +610,10 @@ module ActiveRecord
|
|
598
610
|
|
599
611
|
# SHOW VARIABLES LIKE 'name'
|
600
612
|
def show_variable(name)
|
601
|
-
variables = select_all("
|
613
|
+
variables = select_all("select @@#{name} as 'Value'", 'SCHEMA')
|
602
614
|
variables.first['Value'] unless variables.empty?
|
615
|
+
rescue ActiveRecord::StatementInvalid
|
616
|
+
nil
|
603
617
|
end
|
604
618
|
|
605
619
|
# Returns a table's primary key and belonging sequence.
|
@@ -642,6 +656,21 @@ module ActiveRecord
|
|
642
656
|
end
|
643
657
|
end
|
644
658
|
|
659
|
+
# In MySQL 5.7.5 and up, ONLY_FULL_GROUP_BY affects handling of queries that use
|
660
|
+
# DISTINCT and ORDER BY. It requires the ORDER BY columns in the select list for
|
661
|
+
# distinct queries, and requires that the ORDER BY include the distinct column.
|
662
|
+
# See https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html
|
663
|
+
def columns_for_distinct(columns, orders) # :nodoc:
|
664
|
+
order_columns = orders.reject(&:blank?).map { |s|
|
665
|
+
# Convert Arel node to string
|
666
|
+
s = s.to_sql unless s.is_a?(String)
|
667
|
+
# Remove any ASC/DESC modifiers
|
668
|
+
s.gsub(/\s+(?:ASC|DESC)\b/i, '')
|
669
|
+
}.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" }
|
670
|
+
|
671
|
+
[super, *order_columns].join(', ')
|
672
|
+
end
|
673
|
+
|
645
674
|
def strict_mode?
|
646
675
|
self.class.type_cast_config_to_boolean(@config.fetch(:strict, true))
|
647
676
|
end
|
@@ -707,6 +736,10 @@ module ActiveRecord
|
|
707
736
|
subsubselect = select.clone
|
708
737
|
subsubselect.projections = [key]
|
709
738
|
|
739
|
+
# Materialize subquery by adding distinct
|
740
|
+
# to work with MySQL 5.7.6 which sets optimizer_switch='derived_merge=on'
|
741
|
+
subsubselect.distinct unless select.limit || select.offset || select.orders.any?
|
742
|
+
|
710
743
|
subselect = Arel::SelectManager.new(select.engine)
|
711
744
|
subselect.project Arel.sql(key.name)
|
712
745
|
subselect.from subsubselect.as('__active_record_temp')
|
@@ -811,7 +844,7 @@ module ActiveRecord
|
|
811
844
|
private
|
812
845
|
|
813
846
|
def version
|
814
|
-
@version ||= full_version.
|
847
|
+
@version ||= Version.new(full_version.match(/^\d+\.\d+\.\d+/)[0])
|
815
848
|
end
|
816
849
|
|
817
850
|
def mariadb?
|
@@ -819,7 +852,7 @@ module ActiveRecord
|
|
819
852
|
end
|
820
853
|
|
821
854
|
def supports_rename_index?
|
822
|
-
mariadb? ? false :
|
855
|
+
mariadb? ? false : version >= '5.7.6'
|
823
856
|
end
|
824
857
|
|
825
858
|
def configure_connection
|
@@ -31,7 +31,7 @@ module ActiveRecord
|
|
31
31
|
# It will be mapped to one of the standard Rails SQL types in the <tt>type</tt> attribute.
|
32
32
|
# +null+ determines if this column allows +NULL+ values.
|
33
33
|
def initialize(name, default, cast_type, sql_type = nil, null = true)
|
34
|
-
@name = name
|
34
|
+
@name = name.freeze
|
35
35
|
@cast_type = cast_type
|
36
36
|
@sql_type = sql_type
|
37
37
|
@null = null
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'active_record/connection_adapters/abstract_mysql_adapter'
|
2
2
|
|
3
|
-
gem 'mysql2', '
|
3
|
+
gem 'mysql2', '>= 0.3.13', '< 0.5'
|
4
4
|
require 'mysql2'
|
5
5
|
|
6
6
|
module ActiveRecord
|
@@ -75,7 +75,7 @@ module ActiveRecord
|
|
75
75
|
end
|
76
76
|
|
77
77
|
def quoted_date(value)
|
78
|
-
if value.acts_like?(:time) && value.respond_to?(:usec)
|
78
|
+
if supports_datetime_with_precision? && value.acts_like?(:time) && value.respond_to?(:usec)
|
79
79
|
"#{super}.#{sprintf("%06d", value.usec)}"
|
80
80
|
else
|
81
81
|
super
|
@@ -271,7 +271,7 @@ module ActiveRecord
|
|
271
271
|
end
|
272
272
|
|
273
273
|
def full_version
|
274
|
-
@full_version ||= @connection.
|
274
|
+
@full_version ||= @connection.server_info[:version]
|
275
275
|
end
|
276
276
|
|
277
277
|
def set_field_encoding field_name
|
@@ -57,7 +57,7 @@ module ActiveRecord
|
|
57
57
|
# * <tt>:database</tt> - The name of the database. No default, must be provided.
|
58
58
|
# * <tt>:encoding</tt> - (Optional) Sets the client encoding by executing "SET NAMES <encoding>" after connection.
|
59
59
|
# * <tt>:reconnect</tt> - Defaults to false (See MySQL documentation: http://dev.mysql.com/doc/refman/5.0/en/auto-reconnect.html).
|
60
|
-
# * <tt>:strict</tt> - Defaults to true. Enable STRICT_ALL_TABLES. (See MySQL documentation: http://dev.mysql.com/doc/refman/5.0/en/
|
60
|
+
# * <tt>:strict</tt> - Defaults to true. Enable STRICT_ALL_TABLES. (See MySQL documentation: http://dev.mysql.com/doc/refman/5.0/en/sql-mode.html)
|
61
61
|
# * <tt>:variables</tt> - (Optional) A hash session variables to send as <tt>SET @@SESSION.key = value</tt> on each database connection. Use the value +:default+ to set a variable to its DEFAULT value. (See MySQL documentation: http://dev.mysql.com/doc/refman/5.0/en/set-statement.html).
|
62
62
|
# * <tt>:sslca</tt> - Necessary to use MySQL with an SSL connection.
|
63
63
|
# * <tt>:sslkey</tt> - Necessary to use MySQL with an SSL connection.
|
@@ -245,7 +245,7 @@ module ActiveRecord
|
|
245
245
|
return @client_encoding if @client_encoding
|
246
246
|
|
247
247
|
result = exec_query(
|
248
|
-
"
|
248
|
+
"select @@character_set_client",
|
249
249
|
'SCHEMA')
|
250
250
|
@client_encoding = ENCODINGS[result.rows.last.last]
|
251
251
|
end
|
@@ -15,11 +15,11 @@ module ActiveRecord
|
|
15
15
|
def run(records)
|
16
16
|
nodes = records.reject { |row| @store.key? row['oid'].to_i }
|
17
17
|
mapped, nodes = nodes.partition { |row| @store.key? row['typname'] }
|
18
|
-
ranges, nodes = nodes.partition { |row| row['typtype'] == 'r' }
|
19
|
-
enums, nodes = nodes.partition { |row| row['typtype'] == 'e' }
|
20
|
-
domains, nodes = nodes.partition { |row| row['typtype'] == 'd' }
|
21
|
-
arrays, nodes = nodes.partition { |row| row['typinput'] == 'array_in' }
|
22
|
-
composites, nodes = nodes.partition { |row| row['typelem'] !=
|
18
|
+
ranges, nodes = nodes.partition { |row| row['typtype'] == 'r'.freeze }
|
19
|
+
enums, nodes = nodes.partition { |row| row['typtype'] == 'e'.freeze }
|
20
|
+
domains, nodes = nodes.partition { |row| row['typtype'] == 'd'.freeze }
|
21
|
+
arrays, nodes = nodes.partition { |row| row['typinput'] == 'array_in'.freeze }
|
22
|
+
composites, nodes = nodes.partition { |row| row['typelem'].to_i != 0 }
|
23
23
|
|
24
24
|
mapped.each { |row| register_mapped_type(row) }
|
25
25
|
enums.each { |row| register_enum_type(row) }
|
@@ -29,6 +29,18 @@ module ActiveRecord
|
|
29
29
|
composites.each { |row| register_composite_type(row) }
|
30
30
|
end
|
31
31
|
|
32
|
+
def query_conditions_for_initial_load(type_map)
|
33
|
+
known_type_names = type_map.keys.map { |n| "'#{n}'" }
|
34
|
+
known_type_types = %w('r' 'e' 'd')
|
35
|
+
<<-SQL % [known_type_names.join(", "), known_type_types.join(", ")]
|
36
|
+
WHERE
|
37
|
+
t.typname IN (%s)
|
38
|
+
OR t.typtype IN (%s)
|
39
|
+
OR t.typinput = 'array_in(cstring,oid,integer)'::regprocedure
|
40
|
+
OR t.typelem != 0
|
41
|
+
SQL
|
42
|
+
end
|
43
|
+
|
32
44
|
private
|
33
45
|
def register_mapped_type(row)
|
34
46
|
alias_type row['oid'], row['typname']
|
@@ -86,7 +86,7 @@ module ActiveRecord
|
|
86
86
|
execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}"
|
87
87
|
end
|
88
88
|
|
89
|
-
# Returns the list of all tables in the schema search path
|
89
|
+
# Returns the list of all tables in the schema search path.
|
90
90
|
def tables(name = nil)
|
91
91
|
query(<<-SQL, 'SCHEMA').map { |row| row[0] }
|
92
92
|
SELECT tablename
|
@@ -95,6 +95,16 @@ module ActiveRecord
|
|
95
95
|
SQL
|
96
96
|
end
|
97
97
|
|
98
|
+
def data_sources # :nodoc
|
99
|
+
select_values(<<-SQL, 'SCHEMA')
|
100
|
+
SELECT c.relname
|
101
|
+
FROM pg_class c
|
102
|
+
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
|
103
|
+
WHERE c.relkind IN ('r', 'v','m') -- (r)elation/table, (v)iew, (m)aterialized view
|
104
|
+
AND n.nspname = ANY (current_schemas(false))
|
105
|
+
SQL
|
106
|
+
end
|
107
|
+
|
98
108
|
# Returns true if table exists.
|
99
109
|
# If the schema is not specified as part of +name+ then it will only find tables within
|
100
110
|
# the current schema search path (regardless of permissions to access tables in other schemas)
|
@@ -111,6 +121,7 @@ module ActiveRecord
|
|
111
121
|
AND n.nspname = #{name.schema ? "'#{name.schema}'" : 'ANY (current_schemas(false))'}
|
112
122
|
SQL
|
113
123
|
end
|
124
|
+
alias data_source_exists? table_exists?
|
114
125
|
|
115
126
|
def drop_table(table_name, options = {})
|
116
127
|
execute "DROP TABLE #{quote_table_name(table_name)}#{' CASCADE' if options[:force] == :cascade}"
|
@@ -418,9 +429,7 @@ module ActiveRecord
|
|
418
429
|
rename_table_indexes(table_name, new_name)
|
419
430
|
end
|
420
431
|
|
421
|
-
|
422
|
-
# See TableDefinition#column for details of the options you can use.
|
423
|
-
def add_column(table_name, column_name, type, options = {})
|
432
|
+
def add_column(table_name, column_name, type, options = {}) #:nodoc:
|
424
433
|
clear_cache!
|
425
434
|
super
|
426
435
|
end
|
@@ -468,7 +477,7 @@ module ActiveRecord
|
|
468
477
|
end
|
469
478
|
|
470
479
|
# Renames a column in a table.
|
471
|
-
def rename_column(table_name, column_name, new_column_name)
|
480
|
+
def rename_column(table_name, column_name, new_column_name) #:nodoc:
|
472
481
|
clear_cache!
|
473
482
|
execute "ALTER TABLE #{quote_table_name(table_name)} RENAME COLUMN #{quote_column_name(column_name)} TO #{quote_column_name(new_column_name)}"
|
474
483
|
rename_column_indexes(table_name, column_name, new_column_name)
|
@@ -554,7 +563,7 @@ module ActiveRecord
|
|
554
563
|
when 1, 2; 'smallint'
|
555
564
|
when 3, 4; 'integer'
|
556
565
|
when 5..8; 'bigint'
|
557
|
-
else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with
|
566
|
+
else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with scale 0 instead.")
|
558
567
|
end
|
559
568
|
when 'datetime'
|
560
569
|
return super unless precision
|
@@ -308,12 +308,8 @@ module ActiveRecord
|
|
308
308
|
true
|
309
309
|
end
|
310
310
|
|
311
|
-
# Enable standard-conforming strings if available.
|
312
311
|
def set_standard_conforming_strings
|
313
|
-
|
314
|
-
execute('SET standard_conforming_strings = on', 'SCHEMA') rescue nil
|
315
|
-
ensure
|
316
|
-
self.client_min_messages = old
|
312
|
+
execute('SET standard_conforming_strings = on', 'SCHEMA')
|
317
313
|
end
|
318
314
|
|
319
315
|
def supports_ddl_transactions?
|
@@ -556,6 +552,8 @@ module ActiveRecord
|
|
556
552
|
end
|
557
553
|
|
558
554
|
def load_additional_types(type_map, oids = nil) # :nodoc:
|
555
|
+
initializer = OID::TypeMapInitializer.new(type_map)
|
556
|
+
|
559
557
|
if supports_ranges?
|
560
558
|
query = <<-SQL
|
561
559
|
SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, t.typtype, t.typbasetype
|
@@ -571,11 +569,13 @@ module ActiveRecord
|
|
571
569
|
|
572
570
|
if oids
|
573
571
|
query += "WHERE t.oid::integer IN (%s)" % oids.join(", ")
|
572
|
+
else
|
573
|
+
query += initializer.query_conditions_for_initial_load(type_map)
|
574
574
|
end
|
575
575
|
|
576
|
-
|
577
|
-
|
578
|
-
|
576
|
+
execute_and_clear(query, 'SCHEMA', []) do |records|
|
577
|
+
initializer.run(records)
|
578
|
+
end
|
579
579
|
end
|
580
580
|
|
581
581
|
FEATURE_NOT_SUPPORTED = "0A000" #:nodoc:
|
@@ -673,7 +673,7 @@ module ActiveRecord
|
|
673
673
|
self.client_min_messages = @config[:min_messages] || 'warning'
|
674
674
|
self.schema_search_path = @config[:schema_search_path] || @config[:schema_order]
|
675
675
|
|
676
|
-
# Use standard-conforming strings
|
676
|
+
# Use standard-conforming strings so we don't have to do the E'...' dance.
|
677
677
|
set_standard_conforming_strings
|
678
678
|
|
679
679
|
# If using Active Record's time zone support configure the connection to return
|
@@ -74,18 +74,6 @@ module ActiveRecord
|
|
74
74
|
boolean: { name: "boolean" }
|
75
75
|
}
|
76
76
|
|
77
|
-
class Version
|
78
|
-
include Comparable
|
79
|
-
|
80
|
-
def initialize(version_string)
|
81
|
-
@version = version_string.split('.').map { |v| v.to_i }
|
82
|
-
end
|
83
|
-
|
84
|
-
def <=>(version_string)
|
85
|
-
@version <=> version_string.split('.').map { |v| v.to_i }
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
77
|
class StatementPool < ConnectionAdapters::StatementPool
|
90
78
|
def initialize(connection, max)
|
91
79
|
super
|
@@ -375,10 +363,12 @@ module ActiveRecord
|
|
375
363
|
row['name']
|
376
364
|
end
|
377
365
|
end
|
366
|
+
alias data_sources tables
|
378
367
|
|
379
368
|
def table_exists?(table_name)
|
380
369
|
table_name && tables(nil, table_name).any?
|
381
370
|
end
|
371
|
+
alias data_source_exists? table_exists?
|
382
372
|
|
383
373
|
# Returns an array of +Column+ objects for the table specified by +table_name+.
|
384
374
|
def columns(table_name) #:nodoc:
|
data/lib/active_record/core.rb
CHANGED
@@ -284,17 +284,22 @@ module ActiveRecord
|
|
284
284
|
_run_initialize_callbacks
|
285
285
|
end
|
286
286
|
|
287
|
-
# Initialize an empty model object from +coder+. +coder+
|
288
|
-
# the
|
289
|
-
#
|
287
|
+
# Initialize an empty model object from +coder+. +coder+ should be
|
288
|
+
# the result of previously encoding an Active Record model, using
|
289
|
+
# `encode_with`
|
290
290
|
#
|
291
291
|
# class Post < ActiveRecord::Base
|
292
292
|
# end
|
293
293
|
#
|
294
|
+
# old_post = Post.new(title: "hello world")
|
295
|
+
# coder = {}
|
296
|
+
# old_post.encode_with(coder)
|
297
|
+
#
|
294
298
|
# post = Post.allocate
|
295
|
-
# post.init_with(
|
299
|
+
# post.init_with(coder)
|
296
300
|
# post.title # => 'hello world'
|
297
301
|
def init_with(coder)
|
302
|
+
coder = LegacyYamlAdapter.convert(self.class, coder)
|
298
303
|
@attributes = coder['attributes']
|
299
304
|
|
300
305
|
init_internals
|
@@ -368,6 +373,7 @@ module ActiveRecord
|
|
368
373
|
coder['raw_attributes'] = attributes_before_type_cast
|
369
374
|
coder['attributes'] = @attributes
|
370
375
|
coder['new_record'] = new_record?
|
376
|
+
coder['active_record_yaml_version'] = 0
|
371
377
|
end
|
372
378
|
|
373
379
|
# Returns true if +comparison_object+ is the same exact object, or +comparison_object+
|
@@ -479,16 +485,16 @@ module ActiveRecord
|
|
479
485
|
Hash[methods.map! { |method| [method, public_send(method)] }].with_indifferent_access
|
480
486
|
end
|
481
487
|
|
488
|
+
private
|
489
|
+
|
482
490
|
def set_transaction_state(state) # :nodoc:
|
483
491
|
@transaction_state = state
|
484
492
|
end
|
485
493
|
|
486
494
|
def has_transactional_callbacks? # :nodoc:
|
487
|
-
!_rollback_callbacks.empty? || !_commit_callbacks.empty?
|
495
|
+
!_rollback_callbacks.empty? || !_commit_callbacks.empty?
|
488
496
|
end
|
489
497
|
|
490
|
-
private
|
491
|
-
|
492
498
|
# Updates the attributes on this particular ActiveRecord object so that
|
493
499
|
# if it is associated with a transaction, then the state of the AR object
|
494
500
|
# will be updated to reflect the current state of the transaction
|
@@ -511,6 +517,8 @@ module ActiveRecord
|
|
511
517
|
end
|
512
518
|
|
513
519
|
def update_attributes_from_transaction_state(transaction_state, depth)
|
520
|
+
@reflects_state = [false] if depth == 0
|
521
|
+
|
514
522
|
if transaction_state && transaction_state.finalized? && !has_transactional_callbacks?
|
515
523
|
unless @reflects_state[depth]
|
516
524
|
restore_transaction_record_state if transaction_state.rolledback?
|
@@ -547,7 +555,6 @@ module ActiveRecord
|
|
547
555
|
@txn = nil
|
548
556
|
@_start_transaction_state = {}
|
549
557
|
@transaction_state = nil
|
550
|
-
@reflects_state = [false]
|
551
558
|
end
|
552
559
|
|
553
560
|
def initialize_internals_callback
|
data/lib/active_record/enum.rb
CHANGED
@@ -18,10 +18,9 @@ module ActiveRecord
|
|
18
18
|
# conversation.archived? # => true
|
19
19
|
# conversation.status # => "archived"
|
20
20
|
#
|
21
|
-
# # conversation.
|
21
|
+
# # conversation.status = 1
|
22
22
|
# conversation.status = "archived"
|
23
23
|
#
|
24
|
-
# # conversation.update! status: nil
|
25
24
|
# conversation.status = nil
|
26
25
|
# conversation.status.nil? # => true
|
27
26
|
# conversation.status # => nil
|
@@ -70,7 +69,7 @@ module ActiveRecord
|
|
70
69
|
# Where conditions on an enum attribute must use the ordinal value of an enum.
|
71
70
|
module Enum
|
72
71
|
def self.extended(base) # :nodoc:
|
73
|
-
base.class_attribute(:defined_enums)
|
72
|
+
base.class_attribute(:defined_enums, instance_writer: false)
|
74
73
|
base.defined_enums = {}
|
75
74
|
end
|
76
75
|
|
data/lib/active_record/errors.rb
CHANGED
@@ -71,9 +71,9 @@ module ActiveRecord
|
|
71
71
|
class RecordNotDestroyed < ActiveRecordError
|
72
72
|
attr_reader :record
|
73
73
|
|
74
|
-
def initialize(record)
|
74
|
+
def initialize(message, record = nil)
|
75
75
|
@record = record
|
76
|
-
super()
|
76
|
+
super(message)
|
77
77
|
end
|
78
78
|
end
|
79
79
|
|
@@ -219,11 +219,12 @@ module ActiveRecord
|
|
219
219
|
class UnknownPrimaryKey < ActiveRecordError
|
220
220
|
attr_reader :model
|
221
221
|
|
222
|
-
def initialize(model)
|
223
|
-
|
222
|
+
def initialize(model, description = nil)
|
223
|
+
message = "Unknown primary key for table #{model.table_name} in model #{model}."
|
224
|
+
message += "\n#{description}" if description
|
225
|
+
super(message)
|
224
226
|
@model = model
|
225
227
|
end
|
226
|
-
|
227
228
|
end
|
228
229
|
|
229
230
|
# Raised when a relation cannot be mutated because it's already loaded.
|
@@ -19,7 +19,7 @@ module ActiveRecord
|
|
19
19
|
# On the other hand, we want to monitor the performance of our real database
|
20
20
|
# queries, not the performance of the access to the query cache.
|
21
21
|
IGNORED_PAYLOADS = %w(SCHEMA EXPLAIN CACHE)
|
22
|
-
EXPLAINED_SQLS = /\A\s*(select|update|delete|insert)\b/i
|
22
|
+
EXPLAINED_SQLS = /\A\s*(with|select|update|delete|insert)\b/i
|
23
23
|
def ignore_payload?(payload)
|
24
24
|
payload[:exception] || IGNORED_PAYLOADS.include?(payload[:name]) || payload[:sql] !~ EXPLAINED_SQLS
|
25
25
|
end
|
@@ -534,12 +534,10 @@ module ActiveRecord
|
|
534
534
|
conn.insert_fixture(row, fixture_set_name)
|
535
535
|
end
|
536
536
|
end
|
537
|
-
end
|
538
537
|
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
connection.reset_pk_sequence!(fs.table_name)
|
538
|
+
# Cap primary key sequences to max(pk).
|
539
|
+
if conn.respond_to?(:reset_pk_sequence!)
|
540
|
+
conn.reset_pk_sequence!(fs.table_name)
|
543
541
|
end
|
544
542
|
end
|
545
543
|
end
|
@@ -661,7 +659,7 @@ module ActiveRecord
|
|
661
659
|
row[association.foreign_type] = $1
|
662
660
|
end
|
663
661
|
|
664
|
-
fk_type =
|
662
|
+
fk_type = reflection_class.columns_hash[fk_name].type
|
665
663
|
row[fk_name] = ActiveRecord::FixtureSet.identify(value, fk_type)
|
666
664
|
end
|
667
665
|
when :has_many
|
@@ -703,6 +701,10 @@ module ActiveRecord
|
|
703
701
|
def lhs_key
|
704
702
|
@association.through_reflection.foreign_key
|
705
703
|
end
|
704
|
+
|
705
|
+
def join_table
|
706
|
+
@association.through_reflection.table_name
|
707
|
+
end
|
706
708
|
end
|
707
709
|
|
708
710
|
private
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module LegacyYamlAdapter
|
3
|
+
def self.convert(klass, coder)
|
4
|
+
return coder unless coder.is_a?(Psych::Coder)
|
5
|
+
|
6
|
+
case coder["active_record_yaml_version"]
|
7
|
+
when 0 then coder
|
8
|
+
else
|
9
|
+
if coder["attributes"].is_a?(AttributeSet)
|
10
|
+
coder
|
11
|
+
else
|
12
|
+
Rails41.convert(klass, coder)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module Rails41
|
18
|
+
def self.convert(klass, coder)
|
19
|
+
attributes = klass.attributes_builder
|
20
|
+
.build_from_database(coder["attributes"])
|
21
|
+
new_record = coder["attributes"][klass.primary_key].blank?
|
22
|
+
|
23
|
+
{
|
24
|
+
"attributes" => attributes,
|
25
|
+
"new_record" => new_record,
|
26
|
+
}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -307,9 +307,8 @@ module ActiveRecord
|
|
307
307
|
#
|
308
308
|
# == Reversible Migrations
|
309
309
|
#
|
310
|
-
# Starting with Rails 3.1, you will be able to define reversible migrations.
|
311
310
|
# Reversible migrations are migrations that know how to go +down+ for you.
|
312
|
-
# You simply supply the +up+ logic, and the Migration system
|
311
|
+
# You simply supply the +up+ logic, and the Migration system figures out
|
313
312
|
# how to execute the down commands for you.
|
314
313
|
#
|
315
314
|
# To define a reversible migration, define the +change+ method in your
|
@@ -421,7 +420,10 @@ module ActiveRecord
|
|
421
420
|
new.migrate direction
|
422
421
|
end
|
423
422
|
|
424
|
-
# Disable
|
423
|
+
# Disable the transaction wrapping this migration.
|
424
|
+
# You can still create your own transactions even after calling #disable_ddl_transaction!
|
425
|
+
#
|
426
|
+
# For more details read the {"Transactional Migrations" section above}[rdoc-ref:Migration].
|
425
427
|
def disable_ddl_transaction!
|
426
428
|
@disable_ddl_transaction = true
|
427
429
|
end
|
@@ -653,7 +655,8 @@ module ActiveRecord
|
|
653
655
|
unless @connection.respond_to? :revert
|
654
656
|
unless arguments.empty? || [:execute, :enable_extension, :disable_extension].include?(method)
|
655
657
|
arguments[0] = proper_table_name(arguments.first, table_name_options)
|
656
|
-
if [:rename_table, :add_foreign_key].include?(method)
|
658
|
+
if [:rename_table, :add_foreign_key].include?(method) ||
|
659
|
+
(method == :remove_foreign_key && !arguments.second.is_a?(Hash))
|
657
660
|
arguments[1] = proper_table_name(arguments.second, table_name_options)
|
658
661
|
end
|
659
662
|
end
|
@@ -295,7 +295,7 @@ module ActiveRecord
|
|
295
295
|
def reset_column_information
|
296
296
|
connection.clear_cache!
|
297
297
|
undefine_attribute_methods
|
298
|
-
connection.schema_cache.clear_table_cache!(table_name)
|
298
|
+
connection.schema_cache.clear_table_cache!(table_name)
|
299
299
|
|
300
300
|
@arel_engine = nil
|
301
301
|
@column_names = nil
|
@@ -523,7 +523,7 @@ module ActiveRecord
|
|
523
523
|
# has_destroy_flag? or if a <tt>:reject_if</tt> proc exists for this
|
524
524
|
# association and evaluates to +true+.
|
525
525
|
def reject_new_record?(association_name, attributes)
|
526
|
-
|
526
|
+
will_be_destroyed?(association_name, attributes) || call_reject_if(association_name, attributes)
|
527
527
|
end
|
528
528
|
|
529
529
|
# Determines if a record with the particular +attributes+ should be
|
@@ -532,7 +532,8 @@ module ActiveRecord
|
|
532
532
|
#
|
533
533
|
# Returns false if there is a +destroy_flag+ on the attributes.
|
534
534
|
def call_reject_if(association_name, attributes)
|
535
|
-
return false if
|
535
|
+
return false if will_be_destroyed?(association_name, attributes)
|
536
|
+
|
536
537
|
case callback = self.nested_attributes_options[association_name][:reject_if]
|
537
538
|
when Symbol
|
538
539
|
method(callback).arity == 0 ? send(callback) : send(callback, attributes)
|
@@ -541,6 +542,15 @@ module ActiveRecord
|
|
541
542
|
end
|
542
543
|
end
|
543
544
|
|
545
|
+
# Only take into account the destroy flag if <tt>:allow_destroy</tt> is true
|
546
|
+
def will_be_destroyed?(association_name, attributes)
|
547
|
+
allow_destroy?(association_name) && has_destroy_flag?(attributes)
|
548
|
+
end
|
549
|
+
|
550
|
+
def allow_destroy?(association_name)
|
551
|
+
self.nested_attributes_options[association_name][:allow_destroy]
|
552
|
+
end
|
553
|
+
|
544
554
|
def raise_nested_attributes_record_not_found!(association_name, record_id)
|
545
555
|
raise RecordNotFound, "Couldn't find #{self.class._reflect_on_association(association_name).klass.name} with ID=#{record_id} for #{self.class.name} with ID=#{id}"
|
546
556
|
end
|