activerecord 4.2.0 → 4.2.11
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 +657 -1
- data/lib/active_record.rb +3 -0
- data/lib/active_record/aggregations.rb +6 -3
- data/lib/active_record/association_relation.rb +13 -0
- data/lib/active_record/associations.rb +5 -4
- 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 +13 -5
- data/lib/active_record/associations/builder/association.rb +1 -1
- data/lib/active_record/associations/builder/collection_association.rb +5 -1
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +8 -4
- data/lib/active_record/associations/collection_association.rb +35 -15
- data/lib/active_record/associations/collection_proxy.rb +15 -9
- data/lib/active_record/associations/foreign_association.rb +11 -0
- data/lib/active_record/associations/has_many_association.rb +30 -15
- data/lib/active_record/associations/has_many_through_association.rb +11 -2
- data/lib/active_record/associations/has_one_association.rb +1 -0
- data/lib/active_record/associations/join_dependency.rb +8 -2
- data/lib/active_record/associations/join_dependency/join_association.rb +7 -1
- data/lib/active_record/associations/preloader.rb +4 -4
- data/lib/active_record/associations/preloader/association.rb +5 -1
- data/lib/active_record/associations/singular_association.rb +2 -8
- data/lib/active_record/associations/through_association.rb +11 -6
- data/lib/active_record/attribute.rb +15 -1
- data/lib/active_record/attribute_assignment.rb +2 -2
- data/lib/active_record/attribute_methods.rb +4 -8
- data/lib/active_record/attribute_methods/before_type_cast.rb +5 -0
- data/lib/active_record/attribute_methods/dirty.rb +14 -4
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +5 -1
- data/lib/active_record/attribute_methods/write.rb +1 -1
- data/lib/active_record/attribute_set.rb +4 -0
- data/lib/active_record/attribute_set/builder.rb +32 -12
- data/lib/active_record/attributes.rb +8 -0
- data/lib/active_record/autosave_association.rb +24 -9
- 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 +12 -6
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +23 -3
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -0
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +26 -16
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +87 -24
- data/lib/active_record/connection_adapters/abstract/transaction.rb +2 -6
- data/lib/active_record/connection_adapters/abstract_adapter.rb +25 -7
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +73 -10
- data/lib/active_record/connection_adapters/column.rb +2 -2
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +7 -21
- data/lib/active_record/connection_adapters/mysql_adapter.rb +10 -3
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +9 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +17 -5
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +21 -13
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +12 -12
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +12 -28
- data/lib/active_record/connection_handling.rb +1 -1
- data/lib/active_record/core.rb +28 -15
- data/lib/active_record/counter_cache.rb +1 -1
- 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 +9 -7
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/legacy_yaml_adapter.rb +30 -0
- data/lib/active_record/locking/optimistic.rb +16 -14
- data/lib/active_record/migration.rb +38 -10
- data/lib/active_record/model_schema.rb +4 -2
- data/lib/active_record/nested_attributes.rb +13 -3
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/persistence.rb +7 -4
- data/lib/active_record/railtie.rb +5 -3
- data/lib/active_record/railties/databases.rake +17 -24
- data/lib/active_record/reflection.rb +40 -28
- data/lib/active_record/relation.rb +3 -2
- data/lib/active_record/relation/calculations.rb +10 -3
- data/lib/active_record/relation/delegation.rb +1 -1
- data/lib/active_record/relation/finder_methods.rb +4 -16
- data/lib/active_record/relation/merger.rb +24 -1
- data/lib/active_record/relation/predicate_builder.rb +32 -3
- data/lib/active_record/relation/predicate_builder/array_handler.rb +3 -2
- data/lib/active_record/relation/query_methods.rb +29 -27
- data/lib/active_record/relation/spawn_methods.rb +7 -3
- data/lib/active_record/schema_dumper.rb +1 -1
- data/lib/active_record/schema_migration.rb +1 -4
- data/lib/active_record/scoping/default.rb +1 -0
- data/lib/active_record/tasks/database_tasks.rb +5 -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 +21 -11
- data/lib/active_record/type/boolean.rb +1 -0
- data/lib/active_record/type/date.rb +4 -0
- data/lib/active_record/type/date_time.rb +14 -3
- data/lib/active_record/type/decimal.rb +27 -3
- data/lib/active_record/type/hash_lookup_type_map.rb +8 -2
- data/lib/active_record/type/integer.rb +9 -5
- data/lib/active_record/type/numeric.rb +1 -1
- data/lib/active_record/type/serialized.rb +7 -1
- data/lib/active_record/type/string.rb +4 -0
- data/lib/active_record/type/value.rb +9 -0
- data/lib/active_record/validations/uniqueness.rb +16 -6
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +0 -3
- data/lib/rails/generators/active_record/migration/templates/migration.rb +0 -6
- metadata +9 -7
@@ -14,7 +14,8 @@ module ActiveRecord
|
|
14
14
|
it for 'IN' conditions.
|
15
15
|
MSG
|
16
16
|
|
17
|
-
|
17
|
+
flat_values = values.flatten
|
18
|
+
values = flat_values unless flat_values.include?(nil)
|
18
19
|
end
|
19
20
|
|
20
21
|
return attribute.in([]) if values.empty? && nils.empty?
|
@@ -37,7 +38,7 @@ module ActiveRecord
|
|
37
38
|
array_predicates.inject { |composite, predicate| composite.or(predicate) }
|
38
39
|
end
|
39
40
|
|
40
|
-
module NullPredicate
|
41
|
+
module NullPredicate # :nodoc:
|
41
42
|
def self.or(other)
|
42
43
|
other
|
43
44
|
end
|
@@ -258,7 +258,7 @@ module ActiveRecord
|
|
258
258
|
def _select!(*fields) # :nodoc:
|
259
259
|
fields.flatten!
|
260
260
|
fields.map! do |field|
|
261
|
-
klass.attribute_alias?(field) ? klass.attribute_alias(field) : field
|
261
|
+
klass.attribute_alias?(field) ? klass.attribute_alias(field).to_sym : field
|
262
262
|
end
|
263
263
|
self.select_values += fields
|
264
264
|
self
|
@@ -757,6 +757,9 @@ module ActiveRecord
|
|
757
757
|
|
758
758
|
def from!(value, subquery_name = nil) # :nodoc:
|
759
759
|
self.from_value = [value, subquery_name]
|
760
|
+
if value.is_a? Relation
|
761
|
+
self.bind_values = value.arel.bind_values + value.bind_values + bind_values
|
762
|
+
end
|
760
763
|
self
|
761
764
|
end
|
762
765
|
|
@@ -868,12 +871,11 @@ module ActiveRecord
|
|
868
871
|
|
869
872
|
arel.take(connection.sanitize_limit(limit_value)) if limit_value
|
870
873
|
arel.skip(offset_value.to_i) if offset_value
|
871
|
-
|
872
|
-
arel.group(*group_values.uniq.reject(&:blank?)) unless group_values.empty?
|
874
|
+
arel.group(*arel_columns(group_values.uniq.reject(&:blank?))) unless group_values.empty?
|
873
875
|
|
874
876
|
build_order(arel)
|
875
877
|
|
876
|
-
build_select(arel
|
878
|
+
build_select(arel)
|
877
879
|
|
878
880
|
arel.distinct(distinct_value)
|
879
881
|
arel.from(build_from) if from_value
|
@@ -905,9 +907,9 @@ module ActiveRecord
|
|
905
907
|
def where_unscoping(target_value)
|
906
908
|
target_value = target_value.to_s
|
907
909
|
|
908
|
-
where_values.reject
|
910
|
+
self.where_values = where_values.reject do |rel|
|
909
911
|
case rel
|
910
|
-
when Arel::Nodes::Between, Arel::Nodes::In, Arel::Nodes::NotIn, Arel::Nodes::Equality, Arel::Nodes::NotEqual, Arel::Nodes::LessThanOrEqual, Arel::Nodes::GreaterThanOrEqual
|
912
|
+
when Arel::Nodes::Between, Arel::Nodes::In, Arel::Nodes::NotIn, Arel::Nodes::Equality, Arel::Nodes::NotEqual, Arel::Nodes::LessThan, Arel::Nodes::LessThanOrEqual, Arel::Nodes::GreaterThan, Arel::Nodes::GreaterThanOrEqual
|
911
913
|
subrelation = (rel.left.kind_of?(Arel::Attributes::Attribute) ? rel.left : rel.right)
|
912
914
|
subrelation.name == target_value
|
913
915
|
end
|
@@ -963,12 +965,9 @@ module ActiveRecord
|
|
963
965
|
|
964
966
|
def create_binds(opts)
|
965
967
|
bindable, non_binds = opts.partition do |column, value|
|
966
|
-
|
967
|
-
|
968
|
-
|
969
|
-
else
|
970
|
-
false
|
971
|
-
end
|
968
|
+
PredicateBuilder.can_be_bound?(value) &&
|
969
|
+
@klass.columns_hash.include?(column.to_s) &&
|
970
|
+
!@klass.reflect_on_aggregation(column)
|
972
971
|
end
|
973
972
|
|
974
973
|
association_binds, non_binds = non_binds.partition do |column, value|
|
@@ -978,6 +977,8 @@ module ActiveRecord
|
|
978
977
|
new_opts = {}
|
979
978
|
binds = []
|
980
979
|
|
980
|
+
connection = self.connection
|
981
|
+
|
981
982
|
bindable.each do |(column,value)|
|
982
983
|
binds.push [@klass.columns_hash[column.to_s], value]
|
983
984
|
new_opts[column] = connection.substitute_at(column)
|
@@ -1006,7 +1007,6 @@ module ActiveRecord
|
|
1006
1007
|
case opts
|
1007
1008
|
when Relation
|
1008
1009
|
name ||= 'subquery'
|
1009
|
-
self.bind_values = opts.bind_values + self.bind_values
|
1010
1010
|
opts.arel.as(name.to_s)
|
1011
1011
|
else
|
1012
1012
|
opts
|
@@ -1054,22 +1054,26 @@ module ActiveRecord
|
|
1054
1054
|
manager
|
1055
1055
|
end
|
1056
1056
|
|
1057
|
-
def build_select(arel
|
1058
|
-
if
|
1059
|
-
|
1060
|
-
if (Symbol === field || String === field) && columns_hash.key?(field.to_s)
|
1061
|
-
arel_table[field]
|
1062
|
-
else
|
1063
|
-
field
|
1064
|
-
end
|
1065
|
-
end
|
1066
|
-
|
1067
|
-
arel.project(*expanded_select)
|
1057
|
+
def build_select(arel)
|
1058
|
+
if select_values.any?
|
1059
|
+
arel.project(*arel_columns(select_values.uniq))
|
1068
1060
|
else
|
1069
1061
|
arel.project(@klass.arel_table[Arel.star])
|
1070
1062
|
end
|
1071
1063
|
end
|
1072
1064
|
|
1065
|
+
def arel_columns(columns)
|
1066
|
+
columns.map do |field|
|
1067
|
+
if (Symbol === field || String === field) && columns_hash.key?(field.to_s) && !from_value
|
1068
|
+
arel_table[field]
|
1069
|
+
elsif Symbol === field
|
1070
|
+
connection.quote_table_name(field.to_s)
|
1071
|
+
else
|
1072
|
+
field
|
1073
|
+
end
|
1074
|
+
end
|
1075
|
+
end
|
1076
|
+
|
1073
1077
|
def reverse_sql_order(order_query)
|
1074
1078
|
order_query = ["#{quoted_table_name}.#{quoted_primary_key} ASC"] if order_query.empty?
|
1075
1079
|
|
@@ -1159,13 +1163,11 @@ module ActiveRecord
|
|
1159
1163
|
end
|
1160
1164
|
end
|
1161
1165
|
|
1162
|
-
# This function is recursive just for better readablity.
|
1163
|
-
# #where argument doesn't support more than one level nested hash in real world.
|
1164
1166
|
def add_relations_to_bind_values(attributes)
|
1165
1167
|
if attributes.is_a?(Hash)
|
1166
1168
|
attributes.each_value do |value|
|
1167
1169
|
if value.is_a?(ActiveRecord::Relation)
|
1168
|
-
self.bind_values += value.bind_values
|
1170
|
+
self.bind_values += value.arel.bind_values + value.bind_values
|
1169
1171
|
else
|
1170
1172
|
add_relations_to_bind_values(value)
|
1171
1173
|
end
|
@@ -12,6 +12,7 @@ module ActiveRecord
|
|
12
12
|
|
13
13
|
# Merges in the conditions from <tt>other</tt>, if <tt>other</tt> is an <tt>ActiveRecord::Relation</tt>.
|
14
14
|
# Returns an array representing the intersection of the resulting records with <tt>other</tt>, if <tt>other</tt> is an array.
|
15
|
+
#
|
15
16
|
# Post.where(published: true).joins(:comments).merge( Comment.where(spam: false) )
|
16
17
|
# # Performs a single join query with both where conditions.
|
17
18
|
#
|
@@ -37,11 +38,14 @@ module ActiveRecord
|
|
37
38
|
end
|
38
39
|
|
39
40
|
def merge!(other) # :nodoc:
|
40
|
-
if
|
41
|
+
if other.is_a?(Hash)
|
42
|
+
Relation::HashMerger.new(self, other).merge
|
43
|
+
elsif other.is_a?(Relation)
|
44
|
+
Relation::Merger.new(self, other).merge
|
45
|
+
elsif other.respond_to?(:to_proc)
|
41
46
|
instance_exec(&other)
|
42
47
|
else
|
43
|
-
|
44
|
-
klass.new(self, other).merge
|
48
|
+
raise ArgumentError, "#{other.inspect} is not an ActiveRecord::Relation"
|
45
49
|
end
|
46
50
|
end
|
47
51
|
|
@@ -122,7 +122,7 @@ HEADER
|
|
122
122
|
tbl.print ", id: :bigserial"
|
123
123
|
elsif pkcol.sql_type == 'uuid'
|
124
124
|
tbl.print ", id: :uuid"
|
125
|
-
tbl.print %Q(, default:
|
125
|
+
tbl.print %Q(, default: #{pkcol.default_function.inspect})
|
126
126
|
end
|
127
127
|
else
|
128
128
|
tbl.print ", id: false"
|
@@ -34,10 +34,7 @@ module ActiveRecord
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def drop_table
|
37
|
-
if table_exists?
|
38
|
-
connection.remove_index table_name, name: index_name
|
39
|
-
connection.drop_table(table_name)
|
40
|
-
end
|
37
|
+
connection.drop_table table_name if table_exists?
|
41
38
|
end
|
42
39
|
|
43
40
|
def normalize_migration_number(number)
|
@@ -95,6 +95,7 @@ module ActiveRecord
|
|
95
95
|
end
|
96
96
|
|
97
97
|
def build_default_scope(base_rel = relation) # :nodoc:
|
98
|
+
return if abstract_class?
|
98
99
|
if !Base.is_a?(method(:default_scope).owner)
|
99
100
|
# The user has defined their own default scope method, so call that
|
100
101
|
evaluate_default_scope { default_scope }
|
@@ -130,13 +130,16 @@ module ActiveRecord
|
|
130
130
|
end
|
131
131
|
|
132
132
|
def migrate
|
133
|
+
raise "Empty VERSION provided" if ENV["VERSION"] && ENV["VERSION"].empty?
|
134
|
+
|
133
135
|
verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
|
134
136
|
version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
|
135
137
|
scope = ENV['SCOPE']
|
136
138
|
verbose_was, Migration.verbose = Migration.verbose, verbose
|
137
|
-
Migrator.migrate(
|
139
|
+
Migrator.migrate(migrations_paths, version) do |migration|
|
138
140
|
scope.blank? || scope == migration.scope
|
139
141
|
end
|
142
|
+
ActiveRecord::Base.clear_cache!
|
140
143
|
ensure
|
141
144
|
Migration.verbose = verbose_was
|
142
145
|
end
|
@@ -197,7 +200,7 @@ module ActiveRecord
|
|
197
200
|
load_schema_current(format, file)
|
198
201
|
end
|
199
202
|
|
200
|
-
def schema_file(format =
|
203
|
+
def schema_file(format = ActiveRecord::Base.schema_format)
|
201
204
|
case format
|
202
205
|
when :ruby
|
203
206
|
File.join(db_dir, "schema.rb")
|
@@ -56,21 +56,20 @@ module ActiveRecord
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def structure_dump(filename)
|
59
|
-
args = prepare_command_options
|
59
|
+
args = prepare_command_options
|
60
60
|
args.concat(["--result-file", "#{filename}"])
|
61
61
|
args.concat(["--no-data"])
|
62
62
|
args.concat(["#{configuration['database']}"])
|
63
|
-
|
64
|
-
|
65
|
-
"Make sure `mysqldump` is in your PATH and check the command output for warnings."
|
66
|
-
end
|
63
|
+
|
64
|
+
run_cmd('mysqldump', args, 'dumping')
|
67
65
|
end
|
68
66
|
|
69
67
|
def structure_load(filename)
|
70
|
-
args = prepare_command_options
|
68
|
+
args = prepare_command_options
|
71
69
|
args.concat(['--execute', %{SET FOREIGN_KEY_CHECKS = 0; SOURCE #{filename}; SET FOREIGN_KEY_CHECKS = 1}])
|
72
70
|
args.concat(["--database", "#{configuration['database']}"])
|
73
|
-
|
71
|
+
|
72
|
+
run_cmd('mysql', args, 'loading')
|
74
73
|
end
|
75
74
|
|
76
75
|
private
|
@@ -129,16 +128,31 @@ IDENTIFIED BY '#{configuration['password']}' WITH GRANT OPTION;
|
|
129
128
|
$stdin.gets.strip
|
130
129
|
end
|
131
130
|
|
132
|
-
def prepare_command_options
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
131
|
+
def prepare_command_options
|
132
|
+
{
|
133
|
+
'host' => '--host',
|
134
|
+
'port' => '--port',
|
135
|
+
'socket' => '--socket',
|
136
|
+
'username' => '--user',
|
137
|
+
'password' => '--password',
|
138
|
+
'encoding' => '--default-character-set',
|
139
|
+
'sslca' => '--ssl-ca',
|
140
|
+
'sslcert' => '--ssl-cert',
|
141
|
+
'sslcapath' => '--ssl-capath',
|
142
|
+
'sslcipher' => '--ssl-cipher',
|
143
|
+
'sslkey' => '--ssl-key'
|
144
|
+
}.map { |opt, arg| "#{arg}=#{configuration[opt]}" if configuration[opt] }.compact
|
145
|
+
end
|
146
|
+
|
147
|
+
def run_cmd(cmd, args, action)
|
148
|
+
fail run_cmd_error(cmd, args, action) unless Kernel.system(cmd, *args)
|
149
|
+
end
|
140
150
|
|
141
|
-
|
151
|
+
def run_cmd_error(cmd, args, action)
|
152
|
+
msg = "failed to execute:\n"
|
153
|
+
msg << "#{cmd}"
|
154
|
+
msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n"
|
155
|
+
msg
|
142
156
|
end
|
143
157
|
end
|
144
158
|
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'shellwords'
|
2
|
-
|
3
1
|
module ActiveRecord
|
4
2
|
module Tasks # :nodoc:
|
5
3
|
class PostgreSQLDatabaseTasks # :nodoc:
|
@@ -46,20 +44,22 @@ module ActiveRecord
|
|
46
44
|
|
47
45
|
def structure_dump(filename)
|
48
46
|
set_psql_env
|
47
|
+
args = ['-s', '-x', '-O', '-f', filename]
|
49
48
|
search_path = configuration['schema_search_path']
|
50
49
|
unless search_path.blank?
|
51
|
-
|
50
|
+
args += search_path.split(',').map do |part|
|
51
|
+
"--schema=#{part.strip}"
|
52
|
+
end
|
52
53
|
end
|
53
|
-
|
54
|
-
|
55
|
-
raise 'Error dumping database' unless Kernel.system(command)
|
56
|
-
|
54
|
+
args << configuration['database']
|
55
|
+
run_cmd('pg_dump', args, 'dumping')
|
57
56
|
File.open(filename, "a") { |f| f << "SET search_path TO #{connection.schema_search_path};\n\n" }
|
58
57
|
end
|
59
58
|
|
60
59
|
def structure_load(filename)
|
61
60
|
set_psql_env
|
62
|
-
|
61
|
+
args = [ '-q', '-f', filename, configuration['database'] ]
|
62
|
+
run_cmd('psql', args, 'loading')
|
63
63
|
end
|
64
64
|
|
65
65
|
private
|
@@ -85,6 +85,17 @@ module ActiveRecord
|
|
85
85
|
ENV['PGPASSWORD'] = configuration['password'].to_s if configuration['password']
|
86
86
|
ENV['PGUSER'] = configuration['username'].to_s if configuration['username']
|
87
87
|
end
|
88
|
+
|
89
|
+
def run_cmd(cmd, args, action)
|
90
|
+
fail run_cmd_error(cmd, args, action) unless Kernel.system(cmd, *args)
|
91
|
+
end
|
92
|
+
|
93
|
+
def run_cmd_error(cmd, args, action)
|
94
|
+
msg = "failed to execute:\n"
|
95
|
+
msg << "#{cmd} #{args.join(' ')}\n\n"
|
96
|
+
msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n"
|
97
|
+
msg
|
98
|
+
end
|
88
99
|
end
|
89
100
|
end
|
90
101
|
end
|
@@ -328,9 +328,13 @@ module ActiveRecord
|
|
328
328
|
# Add the record to the current transaction so that the +after_rollback+ and +after_commit+ callbacks
|
329
329
|
# can be called.
|
330
330
|
def add_to_transaction
|
331
|
-
if
|
332
|
-
|
331
|
+
if has_transactional_callbacks?
|
332
|
+
self.class.connection.add_transaction_record(self)
|
333
|
+
else
|
334
|
+
sync_with_transaction_state
|
335
|
+
set_transaction_state(self.class.connection.transaction_state)
|
333
336
|
end
|
337
|
+
remember_transaction_record_state
|
334
338
|
end
|
335
339
|
|
336
340
|
# Executes +method+ within a transaction and captures its return value as a
|
@@ -353,6 +357,10 @@ module ActiveRecord
|
|
353
357
|
raise ActiveRecord::Rollback unless status
|
354
358
|
end
|
355
359
|
status
|
360
|
+
ensure
|
361
|
+
if @transaction_state && @transaction_state.committed?
|
362
|
+
clear_transaction_record_state
|
363
|
+
end
|
356
364
|
end
|
357
365
|
|
358
366
|
protected
|
@@ -360,14 +368,12 @@ module ActiveRecord
|
|
360
368
|
# Save the new record state and id of a record so it can be restored later if a transaction fails.
|
361
369
|
def remember_transaction_record_state #:nodoc:
|
362
370
|
@_start_transaction_state[:id] = id
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
end
|
371
|
+
@_start_transaction_state.reverse_merge!(
|
372
|
+
new_record: @new_record,
|
373
|
+
destroyed: @destroyed,
|
374
|
+
frozen?: frozen?,
|
375
|
+
)
|
369
376
|
@_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) + 1
|
370
|
-
@_start_transaction_state[:frozen?] = frozen?
|
371
377
|
end
|
372
378
|
|
373
379
|
# Clear the new record state and id of a record.
|
@@ -387,10 +393,14 @@ module ActiveRecord
|
|
387
393
|
transaction_level = (@_start_transaction_state[:level] || 0) - 1
|
388
394
|
if transaction_level < 1 || force
|
389
395
|
restore_state = @_start_transaction_state
|
390
|
-
thaw
|
396
|
+
thaw
|
391
397
|
@new_record = restore_state[:new_record]
|
392
398
|
@destroyed = restore_state[:destroyed]
|
393
|
-
|
399
|
+
pk = self.class.primary_key
|
400
|
+
if pk && read_attribute(pk) != restore_state[:id]
|
401
|
+
write_attribute(pk, restore_state[:id])
|
402
|
+
end
|
403
|
+
freeze if restore_state[:frozen?]
|
394
404
|
end
|
395
405
|
end
|
396
406
|
end
|
@@ -16,6 +16,7 @@ module ActiveRecord
|
|
16
16
|
if !ConnectionAdapters::Column::FALSE_VALUES.include?(value)
|
17
17
|
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
18
18
|
You attempted to assign a value which is not explicitly `true` or `false`
|
19
|
+
(#{value.inspect})
|
19
20
|
to a boolean column. Currently this value casts to `false`. This will
|
20
21
|
change to match Ruby's semantics, and will cast to `true` in Rails 5.
|
21
22
|
If you would like to maintain the current behavior, you should
|
@@ -8,17 +8,28 @@ module ActiveRecord
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def type_cast_for_database(value)
|
11
|
+
return super unless value.acts_like?(:time)
|
12
|
+
|
11
13
|
zone_conversion_method = ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal
|
12
14
|
|
13
|
-
if value.
|
14
|
-
value.send(zone_conversion_method)
|
15
|
+
if value.respond_to?(zone_conversion_method)
|
16
|
+
value = value.send(zone_conversion_method)
|
17
|
+
end
|
18
|
+
|
19
|
+
return value unless has_precision?
|
20
|
+
|
21
|
+
result = value.to_s(:db)
|
22
|
+
if value.respond_to?(:usec) && (1..6).cover?(precision)
|
23
|
+
"#{result}.#{sprintf("%0#{precision}d", value.usec / 10 ** (6 - precision))}"
|
15
24
|
else
|
16
|
-
|
25
|
+
result
|
17
26
|
end
|
18
27
|
end
|
19
28
|
|
20
29
|
private
|
21
30
|
|
31
|
+
alias has_precision? precision
|
32
|
+
|
22
33
|
def cast_value(string)
|
23
34
|
return string unless string.is_a?(::String)
|
24
35
|
return if string.empty?
|