activerecord 3.0.0.beta3 → 3.0.0.beta4

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 (51) hide show
  1. data/CHANGELOG +27 -0
  2. data/lib/active_record.rb +5 -1
  3. data/lib/active_record/aggregations.rb +1 -0
  4. data/lib/active_record/association_preload.rb +1 -1
  5. data/lib/active_record/associations.rb +88 -33
  6. data/lib/active_record/associations/association_collection.rb +12 -11
  7. data/lib/active_record/associations/association_proxy.rb +1 -1
  8. data/lib/active_record/attribute_methods.rb +10 -1
  9. data/lib/active_record/attribute_methods/dirty.rb +50 -50
  10. data/lib/active_record/attribute_methods/primary_key.rb +1 -1
  11. data/lib/active_record/autosave_association.rb +20 -5
  12. data/lib/active_record/base.rb +28 -343
  13. data/lib/active_record/callbacks.rb +23 -34
  14. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +1 -1
  15. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +3 -3
  16. data/lib/active_record/connection_adapters/abstract/database_limits.rb +57 -0
  17. data/lib/active_record/connection_adapters/abstract/database_statements.rb +56 -0
  18. data/lib/active_record/connection_adapters/abstract/query_cache.rb +11 -18
  19. data/lib/active_record/connection_adapters/abstract/quoting.rb +3 -7
  20. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +3 -3
  21. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +61 -7
  22. data/lib/active_record/connection_adapters/abstract_adapter.rb +3 -1
  23. data/lib/active_record/connection_adapters/mysql_adapter.rb +22 -50
  24. data/lib/active_record/connection_adapters/postgresql_adapter.rb +31 -143
  25. data/lib/active_record/connection_adapters/sqlite_adapter.rb +6 -2
  26. data/lib/active_record/counter_cache.rb +105 -0
  27. data/lib/active_record/fixtures.rb +16 -15
  28. data/lib/active_record/locale/en.yml +2 -2
  29. data/lib/active_record/locking/optimistic.rb +37 -16
  30. data/lib/active_record/migration.rb +7 -3
  31. data/lib/active_record/named_scope.rb +1 -5
  32. data/lib/active_record/nested_attributes.rb +13 -2
  33. data/lib/active_record/observer.rb +19 -7
  34. data/lib/active_record/persistence.rb +230 -0
  35. data/lib/active_record/railtie.rb +17 -23
  36. data/lib/active_record/railties/databases.rake +3 -2
  37. data/lib/active_record/relation.rb +5 -2
  38. data/lib/active_record/relation/batches.rb +6 -1
  39. data/lib/active_record/relation/calculations.rb +12 -9
  40. data/lib/active_record/relation/finder_methods.rb +14 -10
  41. data/lib/active_record/relation/query_methods.rb +62 -44
  42. data/lib/active_record/relation/spawn_methods.rb +6 -1
  43. data/lib/active_record/schema_dumper.rb +3 -0
  44. data/lib/active_record/serializers/xml_serializer.rb +30 -56
  45. data/lib/active_record/session_store.rb +1 -1
  46. data/lib/active_record/timestamp.rb +22 -26
  47. data/lib/active_record/transactions.rb +168 -50
  48. data/lib/active_record/validations.rb +33 -49
  49. data/lib/active_record/version.rb +1 -1
  50. data/lib/rails/generators/active_record.rb +6 -9
  51. metadata +27 -10
@@ -307,7 +307,7 @@ module ActiveRecord
307
307
  end
308
308
  end
309
309
 
310
- return true
310
+ sid
311
311
  end
312
312
 
313
313
  def get_session_model(env, sid)
@@ -11,9 +11,6 @@ module ActiveRecord
11
11
  extend ActiveSupport::Concern
12
12
 
13
13
  included do
14
- alias_method_chain :create, :timestamps
15
- alias_method_chain :update, :timestamps
16
-
17
14
  class_inheritable_accessor :record_timestamps, :instance_writer => false
18
15
  self.record_timestamps = true
19
16
  end
@@ -39,35 +36,34 @@ module ActiveRecord
39
36
  save!
40
37
  end
41
38
 
39
+ private
40
+ def create #:nodoc:
41
+ if record_timestamps
42
+ current_time = current_time_from_proper_timezone
42
43
 
43
- private
44
- def create_with_timestamps #:nodoc:
45
- if record_timestamps
46
- current_time = current_time_from_proper_timezone
47
-
48
- write_attribute('created_at', current_time) if respond_to?(:created_at) && created_at.nil?
49
- write_attribute('created_on', current_time) if respond_to?(:created_on) && created_on.nil?
50
-
51
- write_attribute('updated_at', current_time) if respond_to?(:updated_at) && updated_at.nil?
52
- write_attribute('updated_on', current_time) if respond_to?(:updated_on) && updated_on.nil?
53
- end
44
+ write_attribute('created_at', current_time) if respond_to?(:created_at) && created_at.nil?
45
+ write_attribute('created_on', current_time) if respond_to?(:created_on) && created_on.nil?
54
46
 
55
- create_without_timestamps
47
+ write_attribute('updated_at', current_time) if respond_to?(:updated_at) && updated_at.nil?
48
+ write_attribute('updated_on', current_time) if respond_to?(:updated_on) && updated_on.nil?
56
49
  end
57
50
 
58
- def update_with_timestamps(*args) #:nodoc:
59
- if record_timestamps && (!partial_updates? || changed?)
60
- current_time = current_time_from_proper_timezone
51
+ super
52
+ end
61
53
 
62
- write_attribute('updated_at', current_time) if respond_to?(:updated_at)
63
- write_attribute('updated_on', current_time) if respond_to?(:updated_on)
64
- end
54
+ def update(*args) #:nodoc:
55
+ if record_timestamps && (!partial_updates? || changed?)
56
+ current_time = current_time_from_proper_timezone
65
57
 
66
- update_without_timestamps(*args)
67
- end
68
-
69
- def current_time_from_proper_timezone
70
- self.class.default_timezone == :utc ? Time.now.utc : Time.now
58
+ write_attribute('updated_at', current_time) if respond_to?(:updated_at)
59
+ write_attribute('updated_on', current_time) if respond_to?(:updated_on)
71
60
  end
61
+
62
+ super
63
+ end
64
+
65
+ def current_time_from_proper_timezone
66
+ self.class.default_timezone == :utc ? Time.now.utc : Time.now
67
+ end
72
68
  end
73
69
  end
@@ -9,9 +9,7 @@ module ActiveRecord
9
9
  end
10
10
 
11
11
  included do
12
- [:destroy, :save, :save!].each do |method|
13
- alias_method_chain method, :transactions
14
- end
12
+ define_callbacks :commit, :rollback, :terminator => "result == false", :scope => [:kind, :name]
15
13
  end
16
14
 
17
15
  # Transactions are protective blocks where SQL statements are only permanent
@@ -28,10 +26,10 @@ module ActiveRecord
28
26
  # mary.deposit(100)
29
27
  # end
30
28
  #
31
- # This example will only take money from David and give to Mary if neither
32
- # +withdrawal+ nor +deposit+ raises an exception. Exceptions will force a
33
- # ROLLBACK that returns the database to the state before the transaction was
34
- # begun. Be aware, though, that the objects will _not_ have their instance
29
+ # This example will only take money from David and give it to Mary if neither
30
+ # +withdrawal+ nor +deposit+ raise an exception. Exceptions will force a
31
+ # ROLLBACK that returns the database to the state before the transaction
32
+ # began. Be aware, though, that the objects will _not_ have their instance
35
33
  # data returned to their pre-transactional state.
36
34
  #
37
35
  # == Different Active Record classes in a single transaction
@@ -41,16 +39,16 @@ module ActiveRecord
41
39
  # that class. This is because transactions are per-database connection, not
42
40
  # per-model.
43
41
  #
44
- # In this example a <tt>Balance</tt> record is transactionally saved even
45
- # though <tt>transaction</tt> is called on the <tt>Account</tt> class:
42
+ # In this example a +balance+ record is transactionally saved even
43
+ # though +transaction+ is called on the +Account+ class:
46
44
  #
47
45
  # Account.transaction do
48
46
  # balance.save!
49
47
  # account.save!
50
48
  # end
51
49
  #
52
- # Note that the +transaction+ method is also available as a model instance
53
- # method. For example, you can also do this:
50
+ # The +transaction+ method is also available as a model instance method.
51
+ # For example, you can also do this:
54
52
  #
55
53
  # balance.transaction do
56
54
  # balance.save!
@@ -59,9 +57,9 @@ module ActiveRecord
59
57
  #
60
58
  # == Transactions are not distributed across database connections
61
59
  #
62
- # A transaction acts on a single database connection. If you have
60
+ # A transaction acts on a single database connection. If you have
63
61
  # multiple class-specific databases, the transaction will not protect
64
- # interaction among them. One workaround is to begin a transaction
62
+ # interaction among them. One workaround is to begin a transaction
65
63
  # on each class whose models you alter:
66
64
  #
67
65
  # Student.transaction do
@@ -71,16 +69,22 @@ module ActiveRecord
71
69
  # end
72
70
  # end
73
71
  #
74
- # This is a poor solution, but full distributed transactions are beyond
72
+ # This is a poor solution, but fully distributed transactions are beyond
75
73
  # the scope of Active Record.
76
74
  #
77
- # == Save and destroy are automatically wrapped in a transaction
75
+ # == +save+ and +destroy+ are automatically wrapped in a transaction
76
+ #
77
+ # Both +save+ and +destroy+ come wrapped in a transaction that ensures
78
+ # that whatever you do in validations or callbacks will happen under its
79
+ # protected cover. So you can use validations to check for values that
80
+ # the transaction depends on or you can raise exceptions in the callbacks
81
+ # to rollback, including <tt>after_*</tt> callbacks.
78
82
  #
79
- # Both Base#save and Base#destroy come wrapped in a transaction that ensures
80
- # that whatever you do in validations or callbacks will happen under the
81
- # protected cover of a transaction. So you can use validations to check for
82
- # values that the transaction depends on or you can raise exceptions in the
83
- # callbacks to rollback, including <tt>after_*</tt> callbacks.
83
+ # As a consequence changes to the database are not seen outside your connection
84
+ # until the operation is complete. For example, if you try to update the index
85
+ # of a search engine in +after_save+ the indexer won't see the updated record.
86
+ # The +after_commit+ callback is the only one that is triggered once the update
87
+ # is committed. See below.
84
88
  #
85
89
  # == Exception handling and rolling back
86
90
  #
@@ -88,14 +92,14 @@ module ActiveRecord
88
92
  # be propagated (after triggering the ROLLBACK), so you should be ready to
89
93
  # catch those in your application code.
90
94
  #
91
- # One exception is the ActiveRecord::Rollback exception, which will trigger
95
+ # One exception is the <tt>ActiveRecord::Rollback</tt> exception, which will trigger
92
96
  # a ROLLBACK when raised, but not be re-raised by the transaction block.
93
97
  #
94
- # *Warning*: one should not catch ActiveRecord::StatementInvalid exceptions
95
- # inside a transaction block. StatementInvalid exceptions indicate that an
98
+ # *Warning*: one should not catch <tt>ActiveRecord::StatementInvalid</tt> exceptions
99
+ # inside a transaction block. <tt>ActiveRecord::StatementInvalid</tt> exceptions indicate that an
96
100
  # error occurred at the database level, for example when a unique constraint
97
101
  # is violated. On some database systems, such as PostgreSQL, database errors
98
- # inside a transaction causes the entire transaction to become unusable
102
+ # inside a transaction cause the entire transaction to become unusable
99
103
  # until it's restarted from the beginning. Here is an example which
100
104
  # demonstrates the problem:
101
105
  #
@@ -108,7 +112,7 @@ module ActiveRecord
108
112
  # rescue ActiveRecord::StatementInvalid
109
113
  # # ...which we ignore.
110
114
  # end
111
- #
115
+ #
112
116
  # # On PostgreSQL, the transaction is now unusable. The following
113
117
  # # statement will cause a PostgreSQL error, even though the unique
114
118
  # # constraint is no longer violated:
@@ -117,11 +121,12 @@ module ActiveRecord
117
121
  # # ignored until end of transaction block"
118
122
  # end
119
123
  #
120
- # One should restart the entire transaction if a StatementError occurred.
124
+ # One should restart the entire transaction if an
125
+ # <tt>ActiveRecord::StatementInvalid</tt> occurred.
121
126
  #
122
127
  # == Nested transactions
123
128
  #
124
- # #transaction calls can be nested. By default, this makes all database
129
+ # +transaction+ calls can be nested. By default, this makes all database
125
130
  # statements in the nested transaction block become part of the parent
126
131
  # transaction. For example:
127
132
  #
@@ -132,11 +137,11 @@ module ActiveRecord
132
137
  # raise ActiveRecord::Rollback
133
138
  # end
134
139
  # end
135
- #
140
+ #
136
141
  # User.find(:all) # => empty
137
142
  #
138
143
  # It is also possible to requires a sub-transaction by passing
139
- # <tt>:requires_new => true</tt>. If anything goes wrong, the
144
+ # <tt>:requires_new => true</tt>. If anything goes wrong, the
140
145
  # database rolls back to the beginning of the sub-transaction
141
146
  # without rolling back the parent transaction. For example:
142
147
  #
@@ -147,7 +152,7 @@ module ActiveRecord
147
152
  # raise ActiveRecord::Rollback
148
153
  # end
149
154
  # end
150
- #
155
+ #
151
156
  # User.find(:all) # => Returns only Kotori
152
157
  #
153
158
  # Most databases don't support true nested transactions. At the time of
@@ -157,16 +162,31 @@ module ActiveRecord
157
162
  # http://dev.mysql.com/doc/refman/5.0/en/savepoints.html
158
163
  # for more information about savepoints.
159
164
  #
165
+ # === Callbacks
166
+ #
167
+ # There are two types of callbacks associated with committing and rolling back transactions:
168
+ # +after_commit+ and +after_rollback+.
169
+ #
170
+ # +after_commit+ callbacks are called on every record saved or destroyed within a
171
+ # transaction immediately after the transaction is committed. +after_rollback+ callbacks
172
+ # are called on every record saved or destroyed within a transaction immediately after the
173
+ # transaction or savepoint is rolled back.
174
+ #
175
+ # These callbacks are useful for interacting with other systems since you will be guaranteed
176
+ # that the callback is only executed when the database is in a permanent state. For example,
177
+ # +after_commit+ is a good spot to put in a hook to clearing a cache since clearing it from
178
+ # within a transaction could trigger the cache to be regenerated before the database is updated.
179
+ #
160
180
  # === Caveats
161
181
  #
162
182
  # If you're on MySQL, then do not use DDL operations in nested transactions
163
183
  # blocks that are emulated with savepoints. That is, do not execute statements
164
184
  # like 'CREATE TABLE' inside such blocks. This is because MySQL automatically
165
- # releases all savepoints upon executing a DDL operation. When #transaction
185
+ # releases all savepoints upon executing a DDL operation. When +transaction+
166
186
  # is finished and tries to release the savepoint it created earlier, a
167
187
  # database error will occur because the savepoint has already been
168
188
  # automatically released. The following example demonstrates the problem:
169
- #
189
+ #
170
190
  # Model.connection.transaction do # BEGIN
171
191
  # Model.connection.transaction(:requires_new => true) do # CREATE SAVEPOINT active_record_1
172
192
  # Model.connection.create_table(...) # active_record_1 now automatically released
@@ -181,6 +201,24 @@ module ActiveRecord
181
201
  # See the ConnectionAdapters::DatabaseStatements#transaction API docs.
182
202
  connection.transaction(options, &block)
183
203
  end
204
+
205
+ def after_commit(*args, &block)
206
+ options = args.last
207
+ if options.is_a?(Hash) && options[:on]
208
+ options[:if] = Array.wrap(options[:if])
209
+ options[:if] << "transaction_include_action?(:#{options[:on]})"
210
+ end
211
+ set_callback(:commit, :after, *args, &block)
212
+ end
213
+
214
+ def after_rollback(*args, &block)
215
+ options = args.last
216
+ if options.is_a?(Hash) && options[:on]
217
+ options[:if] = Array.wrap(options[:if])
218
+ options[:if] << "transaction_include_action?(:#{options[:on]})"
219
+ end
220
+ set_callback(:rollback, :after, *args, &block)
221
+ end
184
222
  end
185
223
 
186
224
  # See ActiveRecord::Transactions::ClassMethods for detailed documentation.
@@ -188,33 +226,52 @@ module ActiveRecord
188
226
  self.class.transaction(&block)
189
227
  end
190
228
 
191
- def destroy_with_transactions #:nodoc:
192
- with_transaction_returning_status(:destroy_without_transactions)
229
+ def destroy #:nodoc:
230
+ with_transaction_returning_status { super }
193
231
  end
194
232
 
195
- def save_with_transactions(*args) #:nodoc:
196
- rollback_active_record_state! { with_transaction_returning_status(:save_without_transactions, *args) }
233
+ def save(*) #:nodoc:
234
+ rollback_active_record_state! do
235
+ with_transaction_returning_status { super }
236
+ end
197
237
  end
198
238
 
199
- def save_with_transactions! #:nodoc:
200
- rollback_active_record_state! { self.class.transaction { save_without_transactions! } }
239
+ def save!(*) #:nodoc:
240
+ with_transaction_returning_status { super }
201
241
  end
202
242
 
203
243
  # Reset id and @new_record if the transaction rolls back.
204
244
  def rollback_active_record_state!
205
- id_present = has_attribute?(self.class.primary_key)
206
- previous_id = id
207
- previous_new_record = new_record?
245
+ remember_transaction_record_state
208
246
  yield
209
247
  rescue Exception
210
- @new_record = previous_new_record
211
- if id_present
212
- self.id = previous_id
213
- else
214
- @attributes.delete(self.class.primary_key)
215
- @attributes_cache.delete(self.class.primary_key)
216
- end
248
+ restore_transaction_record_state
217
249
  raise
250
+ ensure
251
+ clear_transaction_record_state
252
+ end
253
+
254
+ # Call the after_commit callbacks
255
+ def committed! #:nodoc:
256
+ _run_commit_callbacks
257
+ ensure
258
+ clear_transaction_record_state
259
+ end
260
+
261
+ # Call the after rollback callbacks. The restore_state argument indicates if the record
262
+ # state should be rolled back to the beginning or just to the last savepoint.
263
+ def rolledback!(force_restore_state = false) #:nodoc:
264
+ _run_rollback_callbacks
265
+ ensure
266
+ restore_transaction_record_state(force_restore_state)
267
+ end
268
+
269
+ # Add the record to the current transaction so that the :after_rollback and :after_commit callbacks
270
+ # can be called.
271
+ def add_to_transaction
272
+ if self.class.connection.add_transaction_record(self)
273
+ remember_transaction_record_state
274
+ end
218
275
  end
219
276
 
220
277
  # Executes +method+ within a transaction and captures its return value as a
@@ -223,13 +280,74 @@ module ActiveRecord
223
280
  #
224
281
  # This method is available within the context of an ActiveRecord::Base
225
282
  # instance.
226
- def with_transaction_returning_status(method, *args)
283
+ def with_transaction_returning_status
227
284
  status = nil
228
285
  self.class.transaction do
229
- status = send(method, *args)
286
+ add_to_transaction
287
+ status = yield
230
288
  raise ActiveRecord::Rollback unless status
231
289
  end
232
290
  status
233
291
  end
292
+
293
+ protected
294
+
295
+ # Save the new record state and id of a record so it can be restored later if a transaction fails.
296
+ def remember_transaction_record_state #:nodoc
297
+ @_start_transaction_state ||= {}
298
+ unless @_start_transaction_state.include?(:new_record)
299
+ @_start_transaction_state[:id] = id if has_attribute?(self.class.primary_key)
300
+ @_start_transaction_state[:new_record] = @new_record
301
+ end
302
+ unless @_start_transaction_state.include?(:destroyed)
303
+ @_start_transaction_state[:destroyed] = @destroyed
304
+ end
305
+ @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) + 1
306
+ end
307
+
308
+ # Clear the new record state and id of a record.
309
+ def clear_transaction_record_state #:nodoc
310
+ if defined?(@_start_transaction_state)
311
+ @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1
312
+ remove_instance_variable(:@_start_transaction_state) if @_start_transaction_state[:level] < 1
313
+ end
314
+ end
315
+
316
+ # Restore the new record state and id of a record that was previously saved by a call to save_record_state.
317
+ def restore_transaction_record_state(force = false) #:nodoc
318
+ if defined?(@_start_transaction_state)
319
+ @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1
320
+ if @_start_transaction_state[:level] < 1
321
+ restore_state = remove_instance_variable(:@_start_transaction_state)
322
+ if restore_state
323
+ @new_record = restore_state[:new_record]
324
+ @destroyed = restore_state[:destroyed]
325
+ if restore_state[:id]
326
+ self.id = restore_state[:id]
327
+ else
328
+ @attributes.delete(self.class.primary_key)
329
+ @attributes_cache.delete(self.class.primary_key)
330
+ end
331
+ end
332
+ end
333
+ end
334
+ end
335
+
336
+ # Determine if a record was created or destroyed in a transaction. State should be one of :new_record or :destroyed.
337
+ def transaction_record_state(state) #:nodoc
338
+ @_start_transaction_state[state] if defined?(@_start_transaction_state)
339
+ end
340
+
341
+ # Determine if a transaction included an action for :create, :update, or :destroy. Used in filtering callbacks.
342
+ def transaction_include_action?(action) #:nodoc
343
+ case action
344
+ when :create
345
+ transaction_record_state(:new_record)
346
+ when :destroy
347
+ destroyed?
348
+ when :update
349
+ !(transaction_record_state(:new_record) || destroyed?)
350
+ end
351
+ end
234
352
  end
235
353
  end
@@ -19,11 +19,6 @@ module ActiveRecord
19
19
  extend ActiveSupport::Concern
20
20
  include ActiveModel::Validations
21
21
 
22
- included do
23
- alias_method_chain :save, :validation
24
- alias_method_chain :save!, :validation
25
- end
26
-
27
22
  module ClassMethods
28
23
  # Creates an object just like Base.create but calls save! instead of save
29
24
  # so an exception is raised if the record is invalid.
@@ -39,59 +34,48 @@ module ActiveRecord
39
34
  end
40
35
  end
41
36
 
42
- module InstanceMethods
43
- # The validation process on save can be skipped by passing false. The regular Base#save method is
44
- # replaced with this when the validations module is mixed in, which it is by default.
45
- def save_with_validation(options=nil)
46
- perform_validation = case options
47
- when NilClass
48
- true
49
- when Hash
50
- options[:validate] != false
51
- else
52
- ActiveSupport::Deprecation.warn "save(#{options}) is deprecated, please give save(:validate => #{options}) instead", caller
53
- options
54
- end
37
+ # The validation process on save can be skipped by passing false. The regular Base#save method is
38
+ # replaced with this when the validations module is mixed in, which it is by default.
39
+ def save(options={})
40
+ perform_validations(options) ? super : false
41
+ end
55
42
 
56
- if perform_validation && valid? || !perform_validation
57
- save_without_validation
58
- else
59
- false
60
- end
61
- end
43
+ # Attempts to save the record just like Base#save but will raise a RecordInvalid exception instead of returning false
44
+ # if the record is not valid.
45
+ def save!(options={})
46
+ perform_validations(options) ? super : raise(RecordInvalid.new(self))
47
+ end
62
48
 
63
- # Attempts to save the record just like Base#save but will raise a RecordInvalid exception instead of returning false
64
- # if the record is not valid.
65
- def save_with_validation!
66
- if valid?
67
- save_without_validation!
68
- else
69
- raise RecordInvalid.new(self)
70
- end
71
- end
49
+ # Runs all the specified validations and returns true if no errors were added otherwise false.
50
+ def valid?(context = nil)
51
+ context ||= (new_record? ? :create : :update)
52
+ super(context)
72
53
 
73
- # Runs all the specified validations and returns true if no errors were added otherwise false.
74
- def valid?
75
- errors.clear
54
+ deprecated_callback_method(:validate)
55
+ deprecated_callback_method(:"validate_on_#{context}")
76
56
 
77
- @_on_validate = new_record? ? :create : :update
78
- _run_validate_callbacks
57
+ errors.empty?
58
+ end
79
59
 
80
- deprecated_callback_method(:validate)
60
+ protected
81
61
 
82
- if new_record?
83
- deprecated_callback_method(:validate_on_create)
84
- else
85
- deprecated_callback_method(:validate_on_update)
86
- end
62
+ def perform_validations(options={})
63
+ perform_validation = case options
64
+ when Hash
65
+ options[:validate] != false
66
+ else
67
+ ActiveSupport::Deprecation.warn "save(#{options}) is deprecated, please give save(:validate => #{options}) instead", caller
68
+ options
69
+ end
87
70
 
88
- errors.empty?
71
+ if perform_validation
72
+ valid?(options.is_a?(Hash) ? options[:context] : nil)
73
+ else
74
+ true
89
75
  end
90
76
  end
91
77
  end
92
78
  end
93
79
 
94
- Dir[File.dirname(__FILE__) + "/validations/*.rb"].sort.each do |path|
95
- filename = File.basename(path)
96
- require "active_record/validations/#{filename}"
97
- end
80
+ require "active_record/validations/associated"
81
+ require "active_record/validations/uniqueness"