activerecord 4.2.4 → 4.2.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +249 -0
  3. data/lib/active_record/aggregations.rb +6 -3
  4. data/lib/active_record/associations/association_scope.rb +1 -1
  5. data/lib/active_record/associations/collection_association.rb +17 -6
  6. data/lib/active_record/associations/collection_proxy.rb +2 -2
  7. data/lib/active_record/associations/has_many_through_association.rb +5 -0
  8. data/lib/active_record/associations/join_dependency/join_association.rb +7 -1
  9. data/lib/active_record/associations/join_dependency.rb +2 -1
  10. data/lib/active_record/associations/preloader/association.rb +5 -1
  11. data/lib/active_record/attribute_assignment.rb +1 -1
  12. data/lib/active_record/attribute_methods/dirty.rb +1 -0
  13. data/lib/active_record/attribute_methods/write.rb +1 -1
  14. data/lib/active_record/attribute_methods.rb +4 -8
  15. data/lib/active_record/attribute_set/builder.rb +21 -11
  16. data/lib/active_record/attribute_set.rb +4 -0
  17. data/lib/active_record/attributes.rb +1 -0
  18. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +1 -1
  19. data/lib/active_record/connection_adapters/abstract/database_statements.rb +7 -2
  20. data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -0
  21. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +2 -2
  22. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +21 -7
  23. data/lib/active_record/connection_adapters/abstract_adapter.rb +12 -1
  24. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +44 -9
  25. data/lib/active_record/connection_adapters/column.rb +1 -1
  26. data/lib/active_record/connection_adapters/mysql2_adapter.rb +5 -19
  27. data/lib/active_record/connection_adapters/mysql_adapter.rb +9 -2
  28. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -0
  29. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +1 -1
  30. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +13 -2
  31. data/lib/active_record/connection_adapters/postgresql_adapter.rb +2 -6
  32. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +2 -12
  33. data/lib/active_record/core.rb +2 -0
  34. data/lib/active_record/enum.rb +2 -3
  35. data/lib/active_record/errors.rb +4 -3
  36. data/lib/active_record/gem_version.rb +1 -1
  37. data/lib/active_record/legacy_yaml_adapter.rb +30 -0
  38. data/lib/active_record/migration.rb +34 -6
  39. data/lib/active_record/model_schema.rb +3 -1
  40. data/lib/active_record/nested_attributes.rb +12 -2
  41. data/lib/active_record/railtie.rb +4 -2
  42. data/lib/active_record/railties/databases.rake +7 -17
  43. data/lib/active_record/reflection.rb +37 -25
  44. data/lib/active_record/relation/calculations.rb +10 -3
  45. data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -1
  46. data/lib/active_record/relation/query_methods.rb +1 -1
  47. data/lib/active_record/relation/spawn_methods.rb +7 -3
  48. data/lib/active_record/schema_migration.rb +1 -4
  49. data/lib/active_record/tasks/database_tasks.rb +4 -1
  50. data/lib/active_record/tasks/mysql_database_tasks.rb +30 -16
  51. data/lib/active_record/tasks/postgresql_database_tasks.rb +19 -8
  52. data/lib/active_record/type/date.rb +4 -0
  53. data/lib/active_record/type/decimal.rb +19 -3
  54. data/lib/active_record/type/value.rb +5 -0
  55. data/lib/active_record/validations/uniqueness.rb +7 -1
  56. data/lib/active_record.rb +2 -0
  57. metadata +8 -8
@@ -36,9 +36,15 @@ module ActiveRecord
36
36
  # Note: not all valid +select+ expressions are valid +count+ expressions. The specifics differ
37
37
  # between databases. In invalid cases, an error from the database is thrown.
38
38
  def count(column_name = nil, options = {})
39
+ if options.present? && !ActiveRecord.const_defined?(:DeprecatedFinders)
40
+ raise ArgumentError, "Relation#count does not support finder options anymore. " \
41
+ "Please build a scope and then call count on it or use the " \
42
+ "activerecord-deprecated_finders gem to enable this functionality."
43
+
44
+ end
45
+
39
46
  # TODO: Remove options argument as soon we remove support to
40
47
  # activerecord-deprecated_finders.
41
- column_name, options = nil, column_name if column_name.is_a?(Hash)
42
48
  calculate(:count, column_name, options)
43
49
  end
44
50
 
@@ -88,7 +94,7 @@ module ActiveRecord
88
94
  #
89
95
  # There are two basic forms of output:
90
96
  #
91
- # * Single aggregate value: The single value is type cast to Fixnum for COUNT, Float
97
+ # * Single aggregate value: The single value is type cast to Integer for COUNT, Float
92
98
  # for AVG, and the given column's type for everything else.
93
99
  #
94
100
  # * Grouped values: This returns an ordered hash of the values and groups them. It
@@ -281,6 +287,7 @@ module ActiveRecord
281
287
  else
282
288
  group_fields = group_attrs
283
289
  end
290
+ group_fields = arel_columns(group_fields)
284
291
 
285
292
  group_aliases = group_fields.map { |field|
286
293
  column_alias_for(field)
@@ -303,7 +310,7 @@ module ActiveRecord
303
310
  operation,
304
311
  distinct).as(aggregate_alias)
305
312
  ]
306
- select_values += select_values unless having_values.empty?
313
+ select_values += self.select_values unless having_values.empty?
307
314
 
308
315
  select_values.concat group_fields.zip(group_aliases).map { |field,aliaz|
309
316
  if field.respond_to?(:as)
@@ -14,7 +14,8 @@ module ActiveRecord
14
14
  it for 'IN' conditions.
15
15
  MSG
16
16
 
17
- values = values.flatten
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?
@@ -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
@@ -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 !other.is_a?(Relation) && other.respond_to?(:to_proc)
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
- klass = other.is_a?(Hash) ? Relation::HashMerger : Relation::Merger
44
- klass.new(self, other).merge
48
+ raise ArgumentError, "#{other.inspect} is not an ActiveRecord::Relation"
45
49
  end
46
50
  end
47
51
 
@@ -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)
@@ -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(Migrator.migrations_paths, version) do |migration|
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
@@ -56,21 +56,20 @@ module ActiveRecord
56
56
  end
57
57
 
58
58
  def structure_dump(filename)
59
- args = prepare_command_options('mysqldump')
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
- unless Kernel.system(*args)
64
- $stderr.puts "Could not dump the database structure. "\
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('mysql')
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
- Kernel.system(*args)
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(command)
133
- args = [command]
134
- args.concat(['--user', configuration['username']]) if configuration['username']
135
- args << "--password=#{configuration['password']}" if configuration['password']
136
- args.concat(['--default-character-set', configuration['encoding']]) if configuration['encoding']
137
- configuration.slice('host', 'port', 'socket').each do |k, v|
138
- args.concat([ "--#{k}", v.to_s ]) if v
139
- end
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
- args
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
- search_path = search_path.split(",").map{|search_path_part| "--schema=#{Shellwords.escape(search_path_part.strip)}" }.join(" ")
50
+ args += search_path.split(',').map do |part|
51
+ "--schema=#{part.strip}"
52
+ end
52
53
  end
53
-
54
- command = "pg_dump -i -s -x -O -f #{Shellwords.escape(filename)} #{search_path} #{Shellwords.escape(configuration['database'])}"
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
- Kernel.system("psql -q -f #{Shellwords.escape(filename)} #{configuration['database']}")
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
@@ -9,6 +9,10 @@ module ActiveRecord
9
9
  ::Date
10
10
  end
11
11
 
12
+ def type_cast_for_database(value)
13
+ type_cast(value)
14
+ end
15
+
12
16
  def type_cast_for_schema(value)
13
17
  "'#{value.to_s(:db)}'"
14
18
  end
@@ -14,11 +14,17 @@ module ActiveRecord
14
14
  private
15
15
 
16
16
  def cast_value(value)
17
- case value
17
+ casted_value = case value
18
18
  when ::Float
19
19
  convert_float_to_big_decimal(value)
20
- when ::Numeric, ::String
20
+ when ::Numeric
21
21
  BigDecimal(value, precision.to_i)
22
+ when ::String
23
+ begin
24
+ value.to_d
25
+ rescue ArgumentError
26
+ BigDecimal(0)
27
+ end
22
28
  else
23
29
  if value.respond_to?(:to_d)
24
30
  value.to_d
@@ -26,11 +32,13 @@ module ActiveRecord
26
32
  cast_value(value.to_s)
27
33
  end
28
34
  end
35
+
36
+ apply_scale(casted_value)
29
37
  end
30
38
 
31
39
  def convert_float_to_big_decimal(value)
32
40
  if precision
33
- BigDecimal(value, float_precision)
41
+ BigDecimal(apply_scale(value), float_precision)
34
42
  else
35
43
  value.to_d
36
44
  end
@@ -43,6 +51,14 @@ module ActiveRecord
43
51
  precision.to_i
44
52
  end
45
53
  end
54
+
55
+ def apply_scale(value)
56
+ if scale
57
+ value.round(scale)
58
+ else
59
+ value
60
+ end
61
+ end
46
62
  end
47
63
  end
48
64
  end
@@ -86,6 +86,11 @@ module ActiveRecord
86
86
  scale == other.scale &&
87
87
  limit == other.limit
88
88
  end
89
+ alias eql? ==
90
+
91
+ def hash
92
+ [self.class, precision, scale, limit].hash
93
+ end
89
94
 
90
95
  private
91
96
 
@@ -17,7 +17,13 @@ module ActiveRecord
17
17
 
18
18
  begin
19
19
  relation = build_relation(finder_class, table, attribute, value)
20
- relation = relation.and(table[finder_class.primary_key.to_sym].not_eq(record.id)) if record.persisted?
20
+ if record.persisted?
21
+ if finder_class.primary_key
22
+ relation = relation.and(table[finder_class.primary_key.to_sym].not_eq(record.id))
23
+ else
24
+ raise UnknownPrimaryKey.new(finder_class, "Can not validate uniqueness for persisted record without primary key.")
25
+ end
26
+ end
21
27
  relation = scope_relation(record, table, relation)
22
28
  relation = finder_class.unscoped.where(relation)
23
29
  relation = relation.merge(options[:conditions]) if options[:conditions]
data/lib/active_record.rb CHANGED
@@ -79,6 +79,8 @@ module ActiveRecord
79
79
  autoload :AttributeMethods
80
80
  autoload :AutosaveAssociation
81
81
 
82
+ autoload :LegacyYamlAdapter
83
+
82
84
  autoload :Relation
83
85
  autoload :AssociationRelation
84
86
  autoload :NullRelation
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.2.4
4
+ version: 4.2.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-24 00:00:00.000000000 Z
11
+ date: 2017-09-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 4.2.4
19
+ version: 4.2.10
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 4.2.4
26
+ version: 4.2.10
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: activemodel
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - '='
32
32
  - !ruby/object:Gem::Version
33
- version: 4.2.4
33
+ version: 4.2.10
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - '='
39
39
  - !ruby/object:Gem::Version
40
- version: 4.2.4
40
+ version: 4.2.10
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: arel
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -194,6 +194,7 @@ files:
194
194
  - lib/active_record/gem_version.rb
195
195
  - lib/active_record/inheritance.rb
196
196
  - lib/active_record/integration.rb
197
+ - lib/active_record/legacy_yaml_adapter.rb
197
198
  - lib/active_record/locale/en.yml
198
199
  - lib/active_record/locking/optimistic.rb
199
200
  - lib/active_record/locking/pessimistic.rb
@@ -303,9 +304,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
303
304
  version: '0'
304
305
  requirements: []
305
306
  rubyforge_project:
306
- rubygems_version: 2.4.7
307
+ rubygems_version: 2.5.2
307
308
  signing_key:
308
309
  specification_version: 4
309
310
  summary: Object-relational mapper framework (part of Rails).
310
311
  test_files: []
311
- has_rdoc: