activerecord 4.2.0 → 4.2.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.

Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +215 -1
  3. data/lib/active_record/associations.rb +4 -3
  4. data/lib/active_record/associations/belongs_to_association.rb +9 -5
  5. data/lib/active_record/associations/builder/collection_association.rb +5 -1
  6. data/lib/active_record/associations/collection_association.rb +17 -2
  7. data/lib/active_record/associations/collection_proxy.rb +5 -0
  8. data/lib/active_record/associations/foreign_association.rb +11 -0
  9. data/lib/active_record/associations/has_many_association.rb +22 -14
  10. data/lib/active_record/associations/has_many_through_association.rb +2 -2
  11. data/lib/active_record/associations/has_one_association.rb +1 -0
  12. data/lib/active_record/associations/through_association.rb +11 -0
  13. data/lib/active_record/attribute.rb +15 -1
  14. data/lib/active_record/attribute_methods/before_type_cast.rb +5 -0
  15. data/lib/active_record/attribute_methods/dirty.rb +7 -3
  16. data/lib/active_record/attribute_methods/time_zone_conversion.rb +5 -1
  17. data/lib/active_record/attribute_set/builder.rb +11 -1
  18. data/lib/active_record/attributes.rb +7 -0
  19. data/lib/active_record/autosave_association.rb +23 -8
  20. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +7 -5
  21. data/lib/active_record/connection_adapters/abstract/database_statements.rb +12 -1
  22. data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -1
  23. data/lib/active_record/connection_adapters/abstract/savepoints.rb +1 -1
  24. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +25 -7
  25. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +38 -6
  26. data/lib/active_record/connection_adapters/abstract/transaction.rb +1 -1
  27. data/lib/active_record/connection_adapters/abstract_adapter.rb +13 -6
  28. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +23 -1
  29. data/lib/active_record/connection_adapters/column.rb +1 -1
  30. data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -1
  31. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +1 -1
  32. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -0
  33. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +9 -0
  34. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -1
  35. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -0
  36. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +3 -3
  37. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +6 -7
  38. data/lib/active_record/connection_adapters/postgresql_adapter.rb +3 -3
  39. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +10 -16
  40. data/lib/active_record/connection_handling.rb +1 -1
  41. data/lib/active_record/core.rb +13 -7
  42. data/lib/active_record/counter_cache.rb +1 -1
  43. data/lib/active_record/fixtures.rb +1 -1
  44. data/lib/active_record/gem_version.rb +1 -1
  45. data/lib/active_record/locking/optimistic.rb +16 -14
  46. data/lib/active_record/migration.rb +1 -1
  47. data/lib/active_record/nested_attributes.rb +1 -1
  48. data/lib/active_record/no_touching.rb +1 -1
  49. data/lib/active_record/persistence.rb +2 -1
  50. data/lib/active_record/railties/databases.rake +2 -2
  51. data/lib/active_record/reflection.rb +1 -1
  52. data/lib/active_record/relation.rb +1 -1
  53. data/lib/active_record/relation/finder_methods.rb +1 -1
  54. data/lib/active_record/relation/predicate_builder.rb +21 -1
  55. data/lib/active_record/relation/predicate_builder/array_handler.rb +1 -1
  56. data/lib/active_record/relation/query_methods.rb +19 -14
  57. data/lib/active_record/schema_dumper.rb +1 -1
  58. data/lib/active_record/transactions.rb +6 -8
  59. data/lib/active_record/type/date_time.rb +14 -3
  60. data/lib/active_record/type/decimal.rb +9 -1
  61. data/lib/active_record/type/integer.rb +9 -5
  62. data/lib/active_record/type/numeric.rb +1 -1
  63. data/lib/active_record/type/serialized.rb +1 -1
  64. data/lib/active_record/type/string.rb +4 -0
  65. data/lib/active_record/type/value.rb +4 -0
  66. data/lib/active_record/validations/uniqueness.rb +1 -1
  67. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +0 -3
  68. data/lib/rails/generators/active_record/migration/templates/migration.rb +0 -6
  69. metadata +8 -7
@@ -39,7 +39,7 @@ module ActiveRecord
39
39
 
40
40
  class PendingMigrationError < MigrationError#:nodoc:
41
41
  def initialize
42
- if defined?(Rails)
42
+ if defined?(Rails.env)
43
43
  super("Migrations are pending. To resolve this issue, run:\n\n\tbin/rake db:migrate RAILS_ENV=#{::Rails.env}")
44
44
  else
45
45
  super("Migrations are pending. To resolve this issue, run:\n\n\tbin/rake db:migrate")
@@ -307,7 +307,7 @@ module ActiveRecord
307
307
  attr_names.each do |association_name|
308
308
  if reflection = _reflect_on_association(association_name)
309
309
  reflection.autosave = true
310
- add_autosave_association_callbacks(reflection)
310
+ define_autosave_validation_callbacks(reflection)
311
311
 
312
312
  nested_attributes_options = self.nested_attributes_options.dup
313
313
  nested_attributes_options[association_name.to_sym] = options
@@ -45,7 +45,7 @@ module ActiveRecord
45
45
  NoTouching.applied_to?(self.class)
46
46
  end
47
47
 
48
- def touch(*)
48
+ def touch(*) # :nodoc:
49
49
  super unless no_touching?
50
50
  end
51
51
  end
@@ -197,7 +197,8 @@ module ActiveRecord
197
197
  def becomes(klass)
198
198
  became = klass.new
199
199
  became.instance_variable_set("@attributes", @attributes)
200
- became.instance_variable_set("@changed_attributes", @changed_attributes) if defined?(@changed_attributes)
200
+ changed_attributes = @changed_attributes if defined?(@changed_attributes)
201
+ became.instance_variable_set("@changed_attributes", changed_attributes || {})
201
202
  became.instance_variable_set("@new_record", new_record?)
202
203
  became.instance_variable_set("@destroyed", destroyed?)
203
204
  became.instance_variable_set("@errors", errors)
@@ -240,7 +240,7 @@ db_namespace = namespace :db do
240
240
  end
241
241
 
242
242
  desc 'Load a schema.rb file into the database'
243
- task :load => [:environment, :load_config] do
243
+ task :load => [:load_config] do
244
244
  ActiveRecord::Tasks::DatabaseTasks.load_schema_current(:ruby, ENV['SCHEMA'])
245
245
  end
246
246
 
@@ -286,7 +286,7 @@ db_namespace = namespace :db do
286
286
  end
287
287
 
288
288
  desc "Recreate the databases from the structure.sql file"
289
- task :load => [:environment, :load_config] do
289
+ task :load => [:load_config] do
290
290
  ActiveRecord::Tasks::DatabaseTasks.load_schema_current(:sql, ENV['DB_STRUCTURE'])
291
291
  end
292
292
 
@@ -499,7 +499,7 @@ module ActiveRecord
499
499
  # returns either nil or the inverse association name that it finds.
500
500
  def automatic_inverse_of
501
501
  if can_find_inverse_of_automatically?(self)
502
- inverse_name = ActiveSupport::Inflector.underscore(options[:as] || active_record.name).to_sym
502
+ inverse_name = ActiveSupport::Inflector.underscore(options[:as] || active_record.name.demodulize).to_sym
503
503
 
504
504
  begin
505
505
  reflection = klass._reflect_on_association(inverse_name)
@@ -568,7 +568,7 @@ module ActiveRecord
568
568
  [name, binds.fetch(name.to_s) {
569
569
  case where.right
570
570
  when Array then where.right.map(&:val)
571
- else
571
+ when Arel::Nodes::Casted
572
572
  where.right.val
573
573
  end
574
574
  }]
@@ -307,7 +307,7 @@ module ActiveRecord
307
307
  relation = relation.where(conditions)
308
308
  else
309
309
  unless conditions == :none
310
- relation = where(primary_key => conditions)
310
+ relation = relation.where(primary_key => conditions)
311
311
  end
312
312
  end
313
313
 
@@ -56,11 +56,18 @@ module ActiveRecord
56
56
  # For polymorphic relationships, find the foreign key and type:
57
57
  # PriceEstimate.where(estimate_of: treasure)
58
58
  if klass && reflection = klass._reflect_on_association(column)
59
- if reflection.polymorphic? && base_class = polymorphic_base_class_from_value(value)
59
+ base_class = polymorphic_base_class_from_value(value)
60
+
61
+ if reflection.polymorphic? && base_class
60
62
  queries << build(table[reflection.foreign_type], base_class)
61
63
  end
62
64
 
63
65
  column = reflection.foreign_key
66
+
67
+ if base_class
68
+ primary_key = reflection.association_primary_key(base_class)
69
+ value = convert_value_to_association_ids(value, primary_key)
70
+ end
64
71
  end
65
72
 
66
73
  queries << build(table[column], value)
@@ -122,5 +129,18 @@ module ActiveRecord
122
129
  @handlers.detect { |klass, _| klass === object }.last
123
130
  end
124
131
  private_class_method :handler_for
132
+
133
+ def self.convert_value_to_association_ids(value, primary_key)
134
+ case value
135
+ when Relation
136
+ value.select(primary_key)
137
+ when Array
138
+ value.map { |v| convert_value_to_association_ids(v, primary_key) }
139
+ when Base
140
+ value._read_attribute(primary_key)
141
+ else
142
+ value
143
+ end
144
+ end
125
145
  end
126
146
  end
@@ -37,7 +37,7 @@ module ActiveRecord
37
37
  array_predicates.inject { |composite, predicate| composite.or(predicate) }
38
38
  end
39
39
 
40
- module NullPredicate
40
+ module NullPredicate # :nodoc:
41
41
  def self.or(other)
42
42
  other
43
43
  end
@@ -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, select_values.uniq)
878
+ build_select(arel)
877
879
 
878
880
  arel.distinct(distinct_value)
879
881
  arel.from(build_from) if from_value
@@ -1006,7 +1008,6 @@ module ActiveRecord
1006
1008
  case opts
1007
1009
  when Relation
1008
1010
  name ||= 'subquery'
1009
- self.bind_values = opts.bind_values + self.bind_values
1010
1011
  opts.arel.as(name.to_s)
1011
1012
  else
1012
1013
  opts
@@ -1054,19 +1055,25 @@ module ActiveRecord
1054
1055
  manager
1055
1056
  end
1056
1057
 
1057
- def build_select(arel, selects)
1058
- if !selects.empty?
1059
- expanded_select = selects.map do |field|
1058
+ def build_select(arel)
1059
+ if select_values.any?
1060
+ arel.project(*arel_columns(select_values.uniq))
1061
+ else
1062
+ arel.project(@klass.arel_table[Arel.star])
1063
+ end
1064
+ end
1065
+
1066
+ def arel_columns(columns)
1067
+ if from_value
1068
+ columns
1069
+ else
1070
+ columns.map do |field|
1060
1071
  if (Symbol === field || String === field) && columns_hash.key?(field.to_s)
1061
1072
  arel_table[field]
1062
1073
  else
1063
1074
  field
1064
1075
  end
1065
1076
  end
1066
-
1067
- arel.project(*expanded_select)
1068
- else
1069
- arel.project(@klass.arel_table[Arel.star])
1070
1077
  end
1071
1078
  end
1072
1079
 
@@ -1159,13 +1166,11 @@ module ActiveRecord
1159
1166
  end
1160
1167
  end
1161
1168
 
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
1169
  def add_relations_to_bind_values(attributes)
1165
1170
  if attributes.is_a?(Hash)
1166
1171
  attributes.each_value do |value|
1167
1172
  if value.is_a?(ActiveRecord::Relation)
1168
- self.bind_values += value.bind_values
1173
+ self.bind_values += value.arel.bind_values + value.bind_values
1169
1174
  else
1170
1175
  add_relations_to_bind_values(value)
1171
1176
  end
@@ -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: "#{pkcol.default_function}") if pkcol.default_function
125
+ tbl.print %Q(, default: #{pkcol.default_function.inspect})
126
126
  end
127
127
  else
128
128
  tbl.print ", id: false"
@@ -360,14 +360,12 @@ module ActiveRecord
360
360
  # Save the new record state and id of a record so it can be restored later if a transaction fails.
361
361
  def remember_transaction_record_state #:nodoc:
362
362
  @_start_transaction_state[:id] = id
363
- unless @_start_transaction_state.include?(:new_record)
364
- @_start_transaction_state[:new_record] = @new_record
365
- end
366
- unless @_start_transaction_state.include?(:destroyed)
367
- @_start_transaction_state[:destroyed] = @destroyed
368
- end
363
+ @_start_transaction_state.reverse_merge!(
364
+ new_record: @new_record,
365
+ destroyed: @destroyed,
366
+ frozen?: frozen?,
367
+ )
369
368
  @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) + 1
370
- @_start_transaction_state[:frozen?] = frozen?
371
369
  end
372
370
 
373
371
  # Clear the new record state and id of a record.
@@ -390,7 +388,7 @@ module ActiveRecord
390
388
  thaw unless restore_state[:frozen?]
391
389
  @new_record = restore_state[:new_record]
392
390
  @destroyed = restore_state[:destroyed]
393
- write_attribute(self.class.primary_key, restore_state[:id])
391
+ write_attribute(self.class.primary_key, restore_state[:id]) if self.class.primary_key
394
392
  end
395
393
  end
396
394
  end
@@ -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.acts_like?(:time)
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
- super
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?
@@ -16,7 +16,7 @@ module ActiveRecord
16
16
  def cast_value(value)
17
17
  case value
18
18
  when ::Float
19
- BigDecimal(value, float_precision)
19
+ convert_float_to_big_decimal(value)
20
20
  when ::Numeric, ::String
21
21
  BigDecimal(value, precision.to_i)
22
22
  else
@@ -28,6 +28,14 @@ module ActiveRecord
28
28
  end
29
29
  end
30
30
 
31
+ def convert_float_to_big_decimal(value)
32
+ if precision
33
+ BigDecimal(value, float_precision)
34
+ else
35
+ value.to_d
36
+ end
37
+ end
38
+
31
39
  def float_precision
32
40
  if precision.to_i > ::Float::DIG + 1
33
41
  ::Float::DIG + 1
@@ -12,13 +12,19 @@ module ActiveRecord
12
12
  :integer
13
13
  end
14
14
 
15
- alias type_cast_for_database type_cast
16
-
17
15
  def type_cast_from_database(value)
18
16
  return if value.nil?
19
17
  value.to_i
20
18
  end
21
19
 
20
+ def type_cast_for_database(value)
21
+ result = type_cast(value)
22
+ if result
23
+ ensure_in_range(result)
24
+ end
25
+ result
26
+ end
27
+
22
28
  protected
23
29
 
24
30
  attr_reader :range
@@ -30,9 +36,7 @@ module ActiveRecord
30
36
  when true then 1
31
37
  when false then 0
32
38
  else
33
- result = value.to_i rescue nil
34
- ensure_in_range(result) if result
35
- result
39
+ value.to_i rescue nil
36
40
  end
37
41
  end
38
42
 
@@ -29,7 +29,7 @@ module ActiveRecord
29
29
  # 'wibble'.to_i will give zero, we want to make sure
30
30
  # that we aren't marking int zero to string zero as
31
31
  # changed.
32
- value.to_s !~ /\A\d+\.?\d*\z/
32
+ value.to_s !~ /\A-?\d+\.?\d*\z/
33
33
  end
34
34
  end
35
35
  end
@@ -29,7 +29,7 @@ module ActiveRecord
29
29
 
30
30
  def changed_in_place?(raw_old_value, value)
31
31
  return false if value.nil?
32
- subtype.changed_in_place?(raw_old_value, coder.dump(value))
32
+ subtype.changed_in_place?(raw_old_value, type_cast_for_database(value))
33
33
  end
34
34
 
35
35
  def accessor
@@ -21,6 +21,10 @@ module ActiveRecord
21
21
  end
22
22
  end
23
23
 
24
+ def text?
25
+ true
26
+ end
27
+
24
28
  private
25
29
 
26
30
  def cast_value(value)
@@ -50,6 +50,10 @@ module ActiveRecord
50
50
 
51
51
  # These predicates are not documented, as I need to look further into
52
52
  # their use, and see if they can be removed entirely.
53
+ def text? # :nodoc:
54
+ false
55
+ end
56
+
53
57
  def number? # :nodoc:
54
58
  false
55
59
  end
@@ -65,7 +65,7 @@ module ActiveRecord
65
65
  value = value.to_s[0, column.limit]
66
66
  end
67
67
 
68
- if !options[:case_sensitive] && value.is_a?(String)
68
+ if !options[:case_sensitive] && value && column.text?
69
69
  # will use SQL LOWER function before comparison, unless it detects a case insensitive collation
70
70
  klass.connection.case_insensitive_comparison(table, attribute, column, value)
71
71
  else
@@ -14,9 +14,6 @@ class <%= migration_class_name %> < ActiveRecord::Migration
14
14
  end
15
15
  <% attributes_with_index.each do |attribute| -%>
16
16
  add_index :<%= table_name %>, :<%= attribute.index_name %><%= attribute.inject_index_options %>
17
- <% end -%>
18
- <% attributes.select(&:reference?).reject(&:polymorphic?).each do |attribute| -%>
19
- add_foreign_key :<%= table_name %>, :<%= attribute.name.pluralize %>
20
17
  <% end -%>
21
18
  end
22
19
  end
@@ -4,9 +4,6 @@ class <%= migration_class_name %> < ActiveRecord::Migration
4
4
  <% attributes.each do |attribute| -%>
5
5
  <%- if attribute.reference? -%>
6
6
  add_reference :<%= table_name %>, :<%= attribute.name %><%= attribute.inject_options %>
7
- <%- unless attribute.polymorphic? -%>
8
- add_foreign_key :<%= table_name %>, :<%= attribute.name.pluralize %>
9
- <%- end -%>
10
7
  <%- else -%>
11
8
  add_column :<%= table_name %>, :<%= attribute.name %>, :<%= attribute.type %><%= attribute.inject_options %>
12
9
  <%- if attribute.has_index? -%>
@@ -29,9 +26,6 @@ class <%= migration_class_name %> < ActiveRecord::Migration
29
26
  <%- if migration_action -%>
30
27
  <%- if attribute.reference? -%>
31
28
  remove_reference :<%= table_name %>, :<%= attribute.name %><%= attribute.inject_options %>
32
- <%- unless attribute.polymorphic? -%>
33
- remove_foreign_key :<%= table_name %>, :<%= attribute.name.pluralize %>
34
- <%- end -%>
35
29
  <%- else -%>
36
30
  <%- if attribute.has_index? -%>
37
31
  remove_index :<%= table_name %>, :<%= attribute.index_name %><%= attribute.inject_index_options %>
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.0
4
+ version: 4.2.1
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: 2014-12-20 00:00:00.000000000 Z
11
+ date: 2015-03-19 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.0
19
+ version: 4.2.1
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.0
26
+ version: 4.2.1
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.0
33
+ version: 4.2.1
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.0
40
+ version: 4.2.1
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: arel
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -84,6 +84,7 @@ files:
84
84
  - lib/active_record/associations/builder/singular_association.rb
85
85
  - lib/active_record/associations/collection_association.rb
86
86
  - lib/active_record/associations/collection_proxy.rb
87
+ - lib/active_record/associations/foreign_association.rb
87
88
  - lib/active_record/associations/has_many_association.rb
88
89
  - lib/active_record/associations/has_many_through_association.rb
89
90
  - lib/active_record/associations/has_one_association.rb
@@ -302,7 +303,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
302
303
  version: '0'
303
304
  requirements: []
304
305
  rubyforge_project:
305
- rubygems_version: 2.2.2
306
+ rubygems_version: 2.4.5
306
307
  signing_key:
307
308
  specification_version: 4
308
309
  summary: Object-relational mapper framework (part of Rails).