activerecord 4.2.0 → 4.2.1.rc1

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 +206 -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 +2 -2
  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 +15 -0
  55. data/lib/active_record/relation/predicate_builder/array_handler.rb +1 -1
  56. data/lib/active_record/relation/query_methods.rb +19 -18
  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 +10 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 255759d343183e4336a3b6262171fca30de612a5
4
- data.tar.gz: 1dcb8b8793917f0b6e382fe0949b10181f53de54
3
+ metadata.gz: 7d994cda5e6f13c062c37a85942c342568f8be89
4
+ data.tar.gz: 1fe18033994d5cfdf6dd0b7d888b40e19639e59f
5
5
  SHA512:
6
- metadata.gz: 6d60768a4a480308e1dbf734ca128c2016dac4503f7f090d2ae47931e5f6a6fcb2daf7c4c984bdd870656c732bd976289cc647ef23ffa33738322539b72b51f3
7
- data.tar.gz: e9bd572c50583b55611e1ad470f6879600a67f1110a60e6ad09e608885a59c0878f7bd6612ee33fa9c73a89ccebed864827d5a559c22986a1835f88f6ecb0a66
6
+ metadata.gz: e3659d347024bc585bb04bc102d0c0c758510fc54ad788765cd1d2c4525939ce3a774150e288af4cc1bc6a96f4f8e29f1c05453453ede3b8416f401603fd43e4
7
+ data.tar.gz: f4c192fb5e0785bd0dc306629efe2d6473e8b8b65001a2cf3d0c1ec33ca97869ca24abff38c0d6561c3e4c3082f7aaf9d63946d69514143ef77907e3e8ef72b4
@@ -1,3 +1,208 @@
1
+ * Fixed ActiveRecord::Relation#becomes! and changed_attributes issues for type column
2
+
3
+ Fixes #17139.
4
+
5
+ *Miklos Fazekas*
6
+
7
+ * `remove_reference` with `foreign_key: true` removes the foreign key before
8
+ removing the column. This fixes a bug where it was not possible to remove
9
+ the column on MySQL.
10
+
11
+ Fixes #18664.
12
+
13
+ *Yves Senn*
14
+
15
+ * Add a `:foreign_key` option to `references` and associated migration
16
+ methods. The model and migration generators now use this option, rather than
17
+ the `add_foreign_key` form.
18
+
19
+ *Sean Griffin*
20
+
21
+ * Fix rounding problem for PostgreSQL timestamp column.
22
+
23
+ If timestamp column have the precision, it need to format according to
24
+ the precision of timestamp column.
25
+
26
+ *Ryuta Kamizono*
27
+
28
+ * Respect the database default charset for `schema_migrations` table.
29
+
30
+ The charset of `version` column in `schema_migrations` table is depend
31
+ on the database default charset and collation rather than the encoding
32
+ of the connection.
33
+
34
+ *Ryuta Kamizono*
35
+
36
+ * Respect custom primary keys for associations when calling `Relation#where`
37
+
38
+ Fixes #18813.
39
+
40
+ *Sean Griffin*
41
+
42
+ * Fixed several edge cases which could result in a counter cache updating
43
+ twice or not updating at all for `has_many` and `has_many :through`.
44
+
45
+ Fixes #10865.
46
+
47
+ *Sean Griffin*
48
+
49
+ * Foreign keys added by migrations were given random, generated names. This
50
+ meant a different `structure.sql` would be generated every time a developer
51
+ ran migrations on their machine.
52
+
53
+ The generated part of foreign key names is now a hash of the table name and
54
+ column name, which is consistent every time you run the migration.
55
+
56
+ *Chris Sinjakli*
57
+
58
+ * Fixed ActiveRecord::Relation#group method when argument is SQL reserved key word:
59
+
60
+ SplitTest.group(:key).count
61
+ Property.group(:value).count
62
+
63
+ *Bogdan Gusiev*
64
+
65
+ * Don't define autosave association callbacks twice from
66
+ `accepts_nested_attributes_for`.
67
+
68
+ Fixes #18704.
69
+
70
+ *Sean Griffin*
71
+
72
+ * Integer types will no longer raise a `RangeError` when assigning an
73
+ attribute, but will instead raise when going to the database.
74
+
75
+ Fixes several vague issues which were never reported directly. See the
76
+ commit message from the commit which added this line for some examples.
77
+
78
+ *Sean Griffin*
79
+
80
+ * Values which would error while being sent to the database (such as an
81
+ ASCII-8BIT string with invalid UTF-8 bytes on Sqlite3), no longer error on
82
+ assignment. They will still error when sent to the database, but you are
83
+ given the ability to re-assign it to a valid value.
84
+
85
+ Fixes #18580.
86
+
87
+ *Sean Griffin*
88
+
89
+ * Don't remove join dependencies in `Relation#exists?`
90
+
91
+ Fixes #18632.
92
+
93
+ *Sean Griffin*
94
+
95
+ * Invalid values assigned to a JSON column are assumed to be `nil`.
96
+
97
+ Fixes #18629.
98
+
99
+ *Sean Griffin*
100
+
101
+ * No longer issue deprecation warning when including a scope with extensions.
102
+ Previously every scope with extension methods was transformed into an
103
+ instance dependent scope. Including such a scope would wrongfully issue a
104
+ deprecation warning. This is no longer the case.
105
+
106
+ Fixes #18467.
107
+
108
+ *Yves Senn*
109
+
110
+ * Correctly use the type provided by `serialize` when updating records using
111
+ optimistic locking.
112
+
113
+ Fixes #18385.
114
+
115
+ *Sean Griffin*
116
+
117
+ * `attribute_will_change!` will no longer cause non-persistable attributes to
118
+ be sent to the database.
119
+
120
+ Fixes #18407.
121
+
122
+ *Sean Griffin*
123
+
124
+ * Format the datetime string according to the precision of the datetime field.
125
+
126
+ Incompatible to rounding behavior between MySQL 5.6 and earlier.
127
+
128
+ In 5.5, when you insert `2014-08-17 12:30:00.999999` the fractional part
129
+ is ignored. In 5.6, it's rounded to `2014-08-17 12:30:01`:
130
+
131
+ http://bugs.mysql.com/bug.php?id=68760
132
+
133
+ *Ryuta Kamizono*
134
+
135
+ * Allow precision option for MySQL datetimes.
136
+
137
+ *Ryuta Kamizono*
138
+
139
+ * Clear query cache on rollback.
140
+
141
+ *Florian Weingarten*
142
+
143
+ * Fixed setting of foreign_key for through associations while building of new record.
144
+
145
+ Fixes #12698.
146
+
147
+ *Ivan Antropov*
148
+
149
+ * Fixed automatic inverse_of for models nested in module.
150
+
151
+ *Andrew McCloud*
152
+
153
+ * Fix `reaping_frequency` option when the value is a string.
154
+
155
+ This usually happens when it is configured using `DATABASE_URL`.
156
+
157
+ *korbin*
158
+
159
+ * Fix error message when trying to create an associated record and the foreign
160
+ key is missing.
161
+
162
+ Before this fix the following exception was being raised:
163
+
164
+ NoMethodError: undefined method `val' for #<Arel::Nodes::BindParam:0x007fc64d19c218>
165
+
166
+ Now the message is:
167
+
168
+ ActiveRecord::UnknownAttributeError: unknown attribute 'foreign_key' for Model.
169
+
170
+ *Rafael Mendonça França*
171
+
172
+ * When a table has a composite primary key, the `primary_key` method for
173
+ SQLite3 and PostgreSQL adapters was only returning the first field of the key.
174
+ Ensures that it will return nil instead, as Active Record doesn't support
175
+ composite primary keys.
176
+
177
+ Fixes #18070.
178
+
179
+ *arthurnn*
180
+
181
+ * Ensure `first!` and friends work on loaded associations.
182
+
183
+ Fixes #18237.
184
+
185
+ *Sean Griffin*
186
+
187
+ * Dump the default `nil` for PostgreSQL UUID primary key.
188
+
189
+ *Ryuta Kamizono*
190
+
191
+ * Don't raise when writing an attribute with an out-of-range datetime passed
192
+ by the user.
193
+
194
+ *Grey Baker*
195
+
196
+ * Fixes bug with 'ActiveRecord::Type::Numeric' that causes negative values to
197
+ be marked as having changed when set to the same negative value.
198
+
199
+ Fixes #18161.
200
+
201
+ *Daniel Fox*
202
+
203
+
204
+ ## Rails 4.2.0 (December 20, 2014) ##
205
+
1
206
  * Introduce `force: :cascade` option for `create_table`. Using this option
2
207
  will recreate tables even if they have dependent objects (like foreign keys).
3
208
  `db/schema.rb` now uses `force: :cascade`. This makes it possible to
@@ -9,7 +214,7 @@
9
214
  before loading the schema. This is left for the user to do.
10
215
  `db:test:prepare` will still purge the database.
11
216
 
12
- Closes #17945.
217
+ Fixes #17945.
13
218
 
14
219
  *Yves Senn*
15
220
 
@@ -116,6 +116,7 @@ module ActiveRecord
116
116
  autoload :Association, 'active_record/associations/association'
117
117
  autoload :SingularAssociation, 'active_record/associations/singular_association'
118
118
  autoload :CollectionAssociation, 'active_record/associations/collection_association'
119
+ autoload :ForeignAssociation, 'active_record/associations/foreign_association'
119
120
  autoload :CollectionProxy, 'active_record/associations/collection_proxy'
120
121
 
121
122
  autoload :BelongsToAssociation, 'active_record/associations/belongs_to_association'
@@ -1011,7 +1012,7 @@ module ActiveRecord
1011
1012
  # record(s) being removed so that callbacks are run. However <tt>delete</tt> and <tt>delete_all</tt> will either
1012
1013
  # do the deletion according to the strategy specified by the <tt>:dependent</tt> option, or
1013
1014
  # if no <tt>:dependent</tt> option is given, then it will follow the default strategy.
1014
- # The default strategy is <tt>:nullify</tt> (set the foreign keys to <tt>nil</tt>), except for
1015
+ # The default strategy is to do nothing (leave the foreign keys with the parent ids set), except for
1015
1016
  # +has_many+ <tt>:through</tt>, where the default strategy is <tt>delete_all</tt> (delete
1016
1017
  # the join records, without running their callbacks).
1017
1018
  #
@@ -1377,7 +1378,7 @@ module ActiveRecord
1377
1378
  # has_one :last_comment, -> { order 'posted_on' }, class_name: "Comment"
1378
1379
  # has_one :project_manager, -> { where role: 'project_manager' }, class_name: "Person"
1379
1380
  # has_one :attachment, as: :attachable
1380
- # has_one :boss, readonly: :true
1381
+ # has_one :boss, -> { readonly }
1381
1382
  # has_one :club, through: :membership
1382
1383
  # has_one :primary_address, -> { where primary: true }, through: :addressables, source: :addressable
1383
1384
  # has_one :credit_card, required: true
@@ -1505,7 +1506,7 @@ module ActiveRecord
1505
1506
  # belongs_to :valid_coupon, ->(o) { where "discounts > ?", o.payments_count },
1506
1507
  # class_name: "Coupon", foreign_key: "coupon_id"
1507
1508
  # belongs_to :attachable, polymorphic: true
1508
- # belongs_to :project, readonly: true
1509
+ # belongs_to :project, -> { readonly }
1509
1510
  # belongs_to :post, counter_cache: true
1510
1511
  # belongs_to :company, touch: true
1511
1512
  # belongs_to :company, touch: :employees_last_updated_at
@@ -68,16 +68,19 @@ module ActiveRecord
68
68
  def increment_counter(counter_cache_name)
69
69
  if foreign_key_present?
70
70
  klass.increment_counter(counter_cache_name, target_id)
71
+ if target && !stale_target?
72
+ target.increment(counter_cache_name)
73
+ end
71
74
  end
72
75
  end
73
76
 
74
77
  # Checks whether record is different to the current target, without loading it
75
78
  def different_target?(record)
76
- record.id != owner[reflection.foreign_key]
79
+ record.id != owner._read_attribute(reflection.foreign_key)
77
80
  end
78
81
 
79
82
  def replace_keys(record)
80
- owner[reflection.foreign_key] = record[reflection.association_primary_key(record.class)]
83
+ owner[reflection.foreign_key] = record._read_attribute(reflection.association_primary_key(record.class))
81
84
  end
82
85
 
83
86
  def remove_keys
@@ -85,7 +88,7 @@ module ActiveRecord
85
88
  end
86
89
 
87
90
  def foreign_key_present?
88
- owner[reflection.foreign_key]
91
+ owner._read_attribute(reflection.foreign_key)
89
92
  end
90
93
 
91
94
  # NOTE - for now, we're only supporting inverse setting from belongs_to back onto
@@ -99,12 +102,13 @@ module ActiveRecord
99
102
  if options[:primary_key]
100
103
  owner.send(reflection.name).try(:id)
101
104
  else
102
- owner[reflection.foreign_key]
105
+ owner._read_attribute(reflection.foreign_key)
103
106
  end
104
107
  end
105
108
 
106
109
  def stale_state
107
- owner[reflection.foreign_key] && owner[reflection.foreign_key].to_s
110
+ result = owner._read_attribute(reflection.foreign_key)
111
+ result && result.to_s
108
112
  end
109
113
  end
110
114
  end
@@ -82,7 +82,11 @@ module ActiveRecord::Associations::Builder
82
82
 
83
83
  def wrap_scope(scope, mod)
84
84
  if scope
85
- proc { |owner| instance_exec(owner, &scope).extending(mod) }
85
+ if scope.arity > 0
86
+ proc { |owner| instance_exec(owner, &scope).extending(mod) }
87
+ else
88
+ proc { instance_exec(&scope).extending(mod) }
89
+ end
86
90
  else
87
91
  proc { extending(mod) }
88
92
  end
@@ -129,6 +129,16 @@ module ActiveRecord
129
129
  first_nth_or_last(:last, *args)
130
130
  end
131
131
 
132
+ def take
133
+ if loaded?
134
+ target.first
135
+ else
136
+ scope.take.tap do |record|
137
+ set_inverse_instance record if record.is_a? ActiveRecord::Base
138
+ end
139
+ end
140
+ end
141
+
132
142
  def build(attributes = {}, &block)
133
143
  if attributes.is_a?(Array)
134
144
  attributes.collect { |attr| build(attr, &block) }
@@ -597,8 +607,13 @@ module ActiveRecord
597
607
  if reflection.is_a?(ActiveRecord::Reflection::ThroughReflection)
598
608
  assoc = owner.association(reflection.through_reflection.name)
599
609
  assoc.reader.any? { |source|
600
- target = source.send(reflection.source_reflection.name)
601
- target.respond_to?(:include?) ? target.include?(record) : target == record
610
+ target_association = source.send(reflection.source_reflection.name)
611
+
612
+ if target_association.respond_to?(:include?)
613
+ target_association.include?(record)
614
+ else
615
+ target_association == record
616
+ end
602
617
  } || target.include?(record)
603
618
  else
604
619
  target.include?(record)
@@ -29,6 +29,7 @@ module ActiveRecord
29
29
  # instantiation of the actual post records.
30
30
  class CollectionProxy < Relation
31
31
  delegate(*(ActiveRecord::Calculations.public_instance_methods - [:count]), to: :scope)
32
+ delegate :find_nth, to: :scope
32
33
 
33
34
  def initialize(klass, association) #:nodoc:
34
35
  @association = association
@@ -226,6 +227,10 @@ module ActiveRecord
226
227
  @association.last(*args)
227
228
  end
228
229
 
230
+ def take
231
+ @association.take
232
+ end
233
+
229
234
  # Returns a new object of the collection type that has been instantiated
230
235
  # with +attributes+ and linked to this object, but have not yet been saved.
231
236
  # You can pass an array of attributes hashes, this will return an array
@@ -0,0 +1,11 @@
1
+ module ActiveRecord::Associations
2
+ module ForeignAssociation
3
+ def foreign_key_present?
4
+ if reflection.klass.primary_key
5
+ owner.attribute_present?(reflection.active_record_primary_key)
6
+ else
7
+ false
8
+ end
9
+ end
10
+ end
11
+ end
@@ -6,6 +6,7 @@ module ActiveRecord
6
6
  # If the association has a <tt>:through</tt> option further specialization
7
7
  # is provided by its child HasManyThroughAssociation.
8
8
  class HasManyAssociation < CollectionAssociation #:nodoc:
9
+ include ForeignAssociation
9
10
 
10
11
  def handle_dependency
11
12
  case options[:dependent]
@@ -84,7 +85,11 @@ module ActiveRecord
84
85
  end
85
86
 
86
87
  def cached_counter_attribute_name(reflection = reflection())
87
- options[:counter_cache] || "#{reflection.name}_count"
88
+ if reflection.options[:counter_cache]
89
+ reflection.options[:counter_cache].to_s
90
+ else
91
+ "#{reflection.name}_count"
92
+ end
88
93
  end
89
94
 
90
95
  def update_counter(difference, reflection = reflection())
@@ -100,7 +105,7 @@ module ActiveRecord
100
105
  end
101
106
 
102
107
  def update_counter_in_memory(difference, reflection = reflection())
103
- if has_cached_counter?(reflection)
108
+ if counter_must_be_updated_by_has_many?(reflection)
104
109
  counter = cached_counter_attribute_name(reflection)
105
110
  owner[counter] += difference
106
111
  owner.send(:clear_attribute_changes, counter) # eww
@@ -117,17 +122,28 @@ module ActiveRecord
117
122
  # it will be decremented twice.
118
123
  #
119
124
  # Hence this method.
120
- def inverse_updates_counter_cache?(reflection = reflection())
125
+ def inverse_which_updates_counter_cache(reflection = reflection())
121
126
  counter_name = cached_counter_attribute_name(reflection)
122
- inverse_updates_counter_named?(counter_name, reflection)
127
+ inverse_which_updates_counter_named(counter_name, reflection)
123
128
  end
129
+ alias inverse_updates_counter_cache? inverse_which_updates_counter_cache
124
130
 
125
- def inverse_updates_counter_named?(counter_name, reflection = reflection())
126
- reflection.klass._reflections.values.any? { |inverse_reflection|
131
+ def inverse_which_updates_counter_named(counter_name, reflection)
132
+ reflection.klass._reflections.values.find { |inverse_reflection|
127
133
  inverse_reflection.belongs_to? &&
128
134
  inverse_reflection.counter_cache_column == counter_name
129
135
  }
130
136
  end
137
+ alias inverse_updates_counter_named? inverse_which_updates_counter_named
138
+
139
+ def inverse_updates_counter_in_memory?(reflection)
140
+ inverse = inverse_which_updates_counter_cache(reflection)
141
+ inverse && inverse == reflection.inverse_of
142
+ end
143
+
144
+ def counter_must_be_updated_by_has_many?(reflection)
145
+ !inverse_updates_counter_in_memory?(reflection) && has_cached_counter?(reflection)
146
+ end
131
147
 
132
148
  def delete_count(method, scope)
133
149
  if method == :delete_all
@@ -153,14 +169,6 @@ module ActiveRecord
153
169
  end
154
170
  end
155
171
 
156
- def foreign_key_present?
157
- if reflection.klass.primary_key
158
- owner.attribute_present?(reflection.association_primary_key)
159
- else
160
- false
161
- end
162
- end
163
-
164
172
  def concat_records(records, *)
165
173
  update_counter_if_success(super, records.length)
166
174
  end