activerecord 3.0.0.beta3 → 3.0.0.beta4

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 (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
@@ -6,7 +6,7 @@ module ActiveRecord
6
6
  # Returns this record's primary key value wrapped in an Array
7
7
  # or nil if the record is a new_record?
8
8
  def to_key
9
- new_record? ? nil : [ send(self.class.primary_key) ]
9
+ new_record? ? nil : [ id ]
10
10
  end
11
11
 
12
12
  module ClassMethods
@@ -1,3 +1,5 @@
1
+ require 'active_support/core_ext/array/wrap'
2
+
1
3
  module ActiveRecord
2
4
  # AutosaveAssociation is a module that takes care of automatically saving
3
5
  # your associations when the parent is saved. In addition to saving, it
@@ -130,8 +132,6 @@ module ActiveRecord
130
132
  ASSOCIATION_TYPES = %w{ has_one belongs_to has_many has_and_belongs_to_many }
131
133
 
132
134
  included do
133
- alias_method_chain :reload, :autosave_associations
134
-
135
135
  ASSOCIATION_TYPES.each do |type|
136
136
  send("valid_keys_for_#{type}_association") << :autosave
137
137
  end
@@ -196,9 +196,9 @@ module ActiveRecord
196
196
  end
197
197
 
198
198
  # Reloads the attributes of the object as usual and removes a mark for destruction.
199
- def reload_with_autosave_associations(options = nil)
199
+ def reload(options = nil)
200
200
  @marked_for_destruction = false
201
- reload_without_autosave_associations(options)
201
+ super
202
202
  end
203
203
 
204
204
  # Marks this record to be destroyed as part of the parents save transaction.
@@ -216,6 +216,12 @@ module ActiveRecord
216
216
  @marked_for_destruction
217
217
  end
218
218
 
219
+ # Returns whether or not this record has been changed in any way (including whether
220
+ # any of its nested autosave associations are likewise changed)
221
+ def changed_for_autosave?
222
+ new_record? || changed? || marked_for_destruction? || nested_records_changed_for_autosave?
223
+ end
224
+
219
225
  private
220
226
 
221
227
  # Returns the record for an association collection that should be validated
@@ -225,12 +231,21 @@ module ActiveRecord
225
231
  if new_record
226
232
  association
227
233
  elsif autosave
228
- association.target.find_all { |record| record.new_record? || record.changed? || record.marked_for_destruction? }
234
+ association.target.find_all { |record| record.changed_for_autosave? }
229
235
  else
230
236
  association.target.find_all { |record| record.new_record? }
231
237
  end
232
238
  end
233
239
 
240
+ # go through nested autosave associations that are loaded in memory (without loading
241
+ # any new ones), and return true if is changed for autosave
242
+ def nested_records_changed_for_autosave?
243
+ self.class.reflect_on_all_autosave_associations.any? do |reflection|
244
+ association = association_instance_get(reflection.name)
245
+ association && Array.wrap(association.target).any?(&:changed_for_autosave?)
246
+ end
247
+ end
248
+
234
249
  # Validate the association if <tt>:validate</tt> or <tt>:autosave</tt> is
235
250
  # turned on for the association specified by +reflection+.
236
251
  def validate_single_association(reflection)
@@ -480,110 +480,6 @@ module ActiveRecord #:nodoc:
480
480
  connection.select_value(sql, "#{name} Count").to_i
481
481
  end
482
482
 
483
- # Resets one or more counter caches to their correct value using an SQL
484
- # count query. This is useful when adding new counter caches, or if the
485
- # counter has been corrupted or modified directly by SQL.
486
- #
487
- # ==== Parameters
488
- #
489
- # * +id+ - The id of the object you wish to reset a counter on.
490
- # * +counters+ - One or more counter names to reset
491
- #
492
- # ==== Examples
493
- #
494
- # # For Post with id #1 records reset the comments_count
495
- # Post.reset_counters(1, :comments)
496
- def reset_counters(id, *counters)
497
- object = find(id)
498
- counters.each do |association|
499
- child_class = reflect_on_association(association).klass
500
- counter_name = child_class.reflect_on_association(self.name.downcase.to_sym).counter_cache_column
501
-
502
- connection.update("UPDATE #{quoted_table_name} SET #{connection.quote_column_name(counter_name)} = #{object.send(association).count} WHERE #{connection.quote_column_name(primary_key)} = #{quote_value(object.id)}", "#{name} UPDATE")
503
- end
504
- end
505
-
506
- # A generic "counter updater" implementation, intended primarily to be
507
- # used by increment_counter and decrement_counter, but which may also
508
- # be useful on its own. It simply does a direct SQL update for the record
509
- # with the given ID, altering the given hash of counters by the amount
510
- # given by the corresponding value:
511
- #
512
- # ==== Parameters
513
- #
514
- # * +id+ - The id of the object you wish to update a counter on or an Array of ids.
515
- # * +counters+ - An Array of Hashes containing the names of the fields
516
- # to update as keys and the amount to update the field by as values.
517
- #
518
- # ==== Examples
519
- #
520
- # # For the Post with id of 5, decrement the comment_count by 1, and
521
- # # increment the action_count by 1
522
- # Post.update_counters 5, :comment_count => -1, :action_count => 1
523
- # # Executes the following SQL:
524
- # # UPDATE posts
525
- # # SET comment_count = comment_count - 1,
526
- # # action_count = action_count + 1
527
- # # WHERE id = 5
528
- #
529
- # # For the Posts with id of 10 and 15, increment the comment_count by 1
530
- # Post.update_counters [10, 15], :comment_count => 1
531
- # # Executes the following SQL:
532
- # # UPDATE posts
533
- # # SET comment_count = comment_count + 1,
534
- # # WHERE id IN (10, 15)
535
- def update_counters(id, counters)
536
- updates = counters.inject([]) { |list, (counter_name, increment)|
537
- sign = increment < 0 ? "-" : "+"
538
- list << "#{connection.quote_column_name(counter_name)} = COALESCE(#{connection.quote_column_name(counter_name)}, 0) #{sign} #{increment.abs}"
539
- }.join(", ")
540
-
541
- if id.is_a?(Array)
542
- ids_list = id.map {|i| quote_value(i)}.join(', ')
543
- condition = "IN (#{ids_list})"
544
- else
545
- condition = "= #{quote_value(id)}"
546
- end
547
-
548
- update_all(updates, "#{connection.quote_column_name(primary_key)} #{condition}")
549
- end
550
-
551
- # Increment a number field by one, usually representing a count.
552
- #
553
- # This is used for caching aggregate values, so that they don't need to be computed every time.
554
- # For example, a DiscussionBoard may cache post_count and comment_count otherwise every time the board is
555
- # shown it would have to run an SQL query to find how many posts and comments there are.
556
- #
557
- # ==== Parameters
558
- #
559
- # * +counter_name+ - The name of the field that should be incremented.
560
- # * +id+ - The id of the object that should be incremented.
561
- #
562
- # ==== Examples
563
- #
564
- # # Increment the post_count column for the record with an id of 5
565
- # DiscussionBoard.increment_counter(:post_count, 5)
566
- def increment_counter(counter_name, id)
567
- update_counters(id, counter_name => 1)
568
- end
569
-
570
- # Decrement a number field by one, usually representing a count.
571
- #
572
- # This works the same as increment_counter but reduces the column value by 1 instead of increasing it.
573
- #
574
- # ==== Parameters
575
- #
576
- # * +counter_name+ - The name of the field that should be decremented.
577
- # * +id+ - The id of the object that should be decremented.
578
- #
579
- # ==== Examples
580
- #
581
- # # Decrement the post_count column for the record with an id of 5
582
- # DiscussionBoard.decrement_counter(:post_count, 5)
583
- def decrement_counter(counter_name, id)
584
- update_counters(id, counter_name => -1)
585
- end
586
-
587
483
  # Attributes named in this macro are protected from mass-assignment,
588
484
  # such as <tt>new(attributes)</tt>,
589
485
  # <tt>update_attributes(attributes)</tt>, or
@@ -772,7 +668,6 @@ module ActiveRecord #:nodoc:
772
668
  name = "#{full_table_name_prefix}#{contained}#{undecorated_table_name(base.name)}#{table_name_suffix}"
773
669
  end
774
670
 
775
- @quoted_table_name = nil
776
671
  set_table_name(name)
777
672
  name
778
673
  end
@@ -806,6 +701,7 @@ module ActiveRecord #:nodoc:
806
701
  # set_table_name "project"
807
702
  # end
808
703
  def set_table_name(value = nil, &block)
704
+ @quoted_table_name = nil
809
705
  define_attr_method :table_name, value, &block
810
706
  end
811
707
  alias :table_name= :set_table_name
@@ -931,6 +827,10 @@ module ActiveRecord #:nodoc:
931
827
  subclasses.each { |klass| klass.reset_inheritable_attributes; klass.reset_column_information }
932
828
  end
933
829
 
830
+ def attribute_method?(attribute)
831
+ super || (table_exists? && column_names.include?(attribute.to_s.sub(/=$/, '')))
832
+ end
833
+
934
834
  # Set the lookup ancestors for ActiveModel.
935
835
  def lookup_ancestors #:nodoc:
936
836
  klass = self
@@ -1275,11 +1175,10 @@ module ActiveRecord #:nodoc:
1275
1175
  with_scope(method_scoping, :overwrite, &block)
1276
1176
  end
1277
1177
 
1278
- # ActiveRecord::Base utilizes the inherited hook to know about new subclasses.
1279
- # You can access the list of currently loaded ActiveRecord::Base subclasses using this accessor.
1178
+ # Returns a list of all subclasses of this class, meaning all descendants.
1280
1179
  def subclasses
1281
1180
  @@subclasses[self] ||= []
1282
- @@subclasses[self] + extra = @@subclasses[self].inject([]) {|list, subclass| list + subclass.subclasses }
1181
+ @@subclasses[self] + @@subclasses[self].inject([]) {|list, subclass| list + subclass.subclasses }
1283
1182
  end
1284
1183
 
1285
1184
  public :subclasses
@@ -1291,7 +1190,7 @@ module ActiveRecord #:nodoc:
1291
1190
  # default_scope order('last_name, first_name')
1292
1191
  # end
1293
1192
  def default_scope(options = {})
1294
- self.default_scoping << construct_finder_arel(options)
1193
+ self.default_scoping << construct_finder_arel(options, default_scoping.pop)
1295
1194
  end
1296
1195
 
1297
1196
  def scoped_methods #:nodoc:
@@ -1320,7 +1219,9 @@ module ActiveRecord #:nodoc:
1320
1219
  begin
1321
1220
  constant = candidate.constantize
1322
1221
  return constant if candidate == constant.to_s
1323
- rescue NameError
1222
+ rescue NameError => e
1223
+ # We don't want to swallow NoMethodError < NameError errors
1224
+ raise e unless e.instance_of?(NameError)
1324
1225
  rescue ArgumentError
1325
1226
  end
1326
1227
  end
@@ -1459,7 +1360,8 @@ module ActiveRecord #:nodoc:
1459
1360
  def replace_bind_variables(statement, values) #:nodoc:
1460
1361
  raise_if_bind_arity_mismatch(statement, statement.count('?'), values.size)
1461
1362
  bound = values.dup
1462
- statement.gsub('?') { quote_bound_value(bound.shift) }
1363
+ c = connection
1364
+ statement.gsub('?') { quote_bound_value(bound.shift, c) }
1463
1365
  end
1464
1366
 
1465
1367
  def replace_named_bind_variables(statement, bind_vars) #:nodoc:
@@ -1491,15 +1393,15 @@ module ActiveRecord #:nodoc:
1491
1393
  expanded
1492
1394
  end
1493
1395
 
1494
- def quote_bound_value(value) #:nodoc:
1396
+ def quote_bound_value(value, c = connection) #:nodoc:
1495
1397
  if value.respond_to?(:map) && !value.acts_like?(:string)
1496
1398
  if value.respond_to?(:empty?) && value.empty?
1497
- connection.quote(nil)
1399
+ c.quote(nil)
1498
1400
  else
1499
- value.map { |v| connection.quote(v) }.join(',')
1401
+ value.map { |v| c.quote(v) }.join(',')
1500
1402
  end
1501
1403
  else
1502
- connection.quote(value)
1404
+ c.quote(value)
1503
1405
  end
1504
1406
  end
1505
1407
 
@@ -1559,7 +1461,14 @@ module ActiveRecord #:nodoc:
1559
1461
  callback(:after_initialize) if respond_to_without_attributes?(:after_initialize)
1560
1462
  cloned_attributes = other.clone_attributes(:read_attribute_before_type_cast)
1561
1463
  cloned_attributes.delete(self.class.primary_key)
1464
+
1562
1465
  @attributes = cloned_attributes
1466
+
1467
+ @changed_attributes = {}
1468
+ attributes_from_column_definition.each do |attr, orig_value|
1469
+ @changed_attributes[attr] = orig_value if field_changed?(attr, orig_value, @attributes[attr])
1470
+ end
1471
+
1563
1472
  clear_aggregation_cache
1564
1473
  @attributes_cache = {}
1565
1474
  @new_record = true
@@ -1620,186 +1529,6 @@ module ActiveRecord #:nodoc:
1620
1529
  quote_value(id, column_for_attribute(self.class.primary_key))
1621
1530
  end
1622
1531
 
1623
- # Returns true if this object hasn't been saved yet -- that is, a record for the object doesn't exist yet; otherwise, returns false.
1624
- def new_record?
1625
- @new_record
1626
- end
1627
-
1628
- # Returns true if this object has been destroyed, otherwise returns false.
1629
- def destroyed?
1630
- @destroyed
1631
- end
1632
-
1633
- # Returns if the record is persisted, i.e. it's not a new record and it was not destroyed.
1634
- def persisted?
1635
- !(new_record? || destroyed?)
1636
- end
1637
-
1638
- # :call-seq:
1639
- # save(options)
1640
- #
1641
- # Saves the model.
1642
- #
1643
- # If the model is new a record gets created in the database, otherwise
1644
- # the existing record gets updated.
1645
- #
1646
- # By default, save always run validations. If any of them fail the action
1647
- # is cancelled and +save+ returns +false+. However, if you supply
1648
- # :validate => false, validations are bypassed altogether. See
1649
- # ActiveRecord::Validations for more information.
1650
- #
1651
- # There's a series of callbacks associated with +save+. If any of the
1652
- # <tt>before_*</tt> callbacks return +false+ the action is cancelled and
1653
- # +save+ returns +false+. See ActiveRecord::Callbacks for further
1654
- # details.
1655
- def save
1656
- create_or_update
1657
- end
1658
-
1659
- # Saves the model.
1660
- #
1661
- # If the model is new a record gets created in the database, otherwise
1662
- # the existing record gets updated.
1663
- #
1664
- # With <tt>save!</tt> validations always run. If any of them fail
1665
- # ActiveRecord::RecordInvalid gets raised. See ActiveRecord::Validations
1666
- # for more information.
1667
- #
1668
- # There's a series of callbacks associated with <tt>save!</tt>. If any of
1669
- # the <tt>before_*</tt> callbacks return +false+ the action is cancelled
1670
- # and <tt>save!</tt> raises ActiveRecord::RecordNotSaved. See
1671
- # ActiveRecord::Callbacks for further details.
1672
- def save!
1673
- create_or_update || raise(RecordNotSaved)
1674
- end
1675
-
1676
- # Deletes the record in the database and freezes this instance to
1677
- # reflect that no changes should be made (since they can't be
1678
- # persisted). Returns the frozen instance.
1679
- #
1680
- # The row is simply removed with a SQL +DELETE+ statement on the
1681
- # record's primary key, and no callbacks are executed.
1682
- #
1683
- # To enforce the object's +before_destroy+ and +after_destroy+
1684
- # callbacks, Observer methods, or any <tt>:dependent</tt> association
1685
- # options, use <tt>#destroy</tt>.
1686
- def delete
1687
- self.class.delete(id) if persisted?
1688
- @destroyed = true
1689
- freeze
1690
- end
1691
-
1692
- # Deletes the record in the database and freezes this instance to reflect that no changes should
1693
- # be made (since they can't be persisted).
1694
- def destroy
1695
- if persisted?
1696
- self.class.unscoped.where(self.class.arel_table[self.class.primary_key].eq(id)).delete_all
1697
- end
1698
-
1699
- @destroyed = true
1700
- freeze
1701
- end
1702
-
1703
- # Returns an instance of the specified +klass+ with the attributes of the current record. This is mostly useful in relation to
1704
- # single-table inheritance structures where you want a subclass to appear as the superclass. This can be used along with record
1705
- # identification in Action Pack to allow, say, <tt>Client < Company</tt> to do something like render <tt>:partial => @client.becomes(Company)</tt>
1706
- # to render that instance using the companies/company partial instead of clients/client.
1707
- #
1708
- # Note: The new instance will share a link to the same attributes as the original class. So any change to the attributes in either
1709
- # instance will affect the other.
1710
- def becomes(klass)
1711
- became = klass.new
1712
- became.instance_variable_set("@attributes", @attributes)
1713
- became.instance_variable_set("@attributes_cache", @attributes_cache)
1714
- became.instance_variable_set("@new_record", new_record?)
1715
- became.instance_variable_set("@destroyed", destroyed?)
1716
- became
1717
- end
1718
-
1719
- # Updates a single attribute and saves the record without going through the normal validation procedure.
1720
- # This is especially useful for boolean flags on existing records. The regular +update_attribute+ method
1721
- # in Base is replaced with this when the validations module is mixed in, which it is by default.
1722
- def update_attribute(name, value)
1723
- send("#{name}=", value)
1724
- save(:validate => false)
1725
- end
1726
-
1727
- # Updates all the attributes from the passed-in Hash and saves the record. If the object is invalid, the saving will
1728
- # fail and false will be returned.
1729
- def update_attributes(attributes)
1730
- self.attributes = attributes
1731
- save
1732
- end
1733
-
1734
- # Updates an object just like Base.update_attributes but calls save! instead of save so an exception is raised if the record is invalid.
1735
- def update_attributes!(attributes)
1736
- self.attributes = attributes
1737
- save!
1738
- end
1739
-
1740
- # Initializes +attribute+ to zero if +nil+ and adds the value passed as +by+ (default is 1).
1741
- # The increment is performed directly on the underlying attribute, no setter is invoked.
1742
- # Only makes sense for number-based attributes. Returns +self+.
1743
- def increment(attribute, by = 1)
1744
- self[attribute] ||= 0
1745
- self[attribute] += by
1746
- self
1747
- end
1748
-
1749
- # Wrapper around +increment+ that saves the record. This method differs from
1750
- # its non-bang version in that it passes through the attribute setter.
1751
- # Saving is not subjected to validation checks. Returns +true+ if the
1752
- # record could be saved.
1753
- def increment!(attribute, by = 1)
1754
- increment(attribute, by).update_attribute(attribute, self[attribute])
1755
- end
1756
-
1757
- # Initializes +attribute+ to zero if +nil+ and subtracts the value passed as +by+ (default is 1).
1758
- # The decrement is performed directly on the underlying attribute, no setter is invoked.
1759
- # Only makes sense for number-based attributes. Returns +self+.
1760
- def decrement(attribute, by = 1)
1761
- self[attribute] ||= 0
1762
- self[attribute] -= by
1763
- self
1764
- end
1765
-
1766
- # Wrapper around +decrement+ that saves the record. This method differs from
1767
- # its non-bang version in that it passes through the attribute setter.
1768
- # Saving is not subjected to validation checks. Returns +true+ if the
1769
- # record could be saved.
1770
- def decrement!(attribute, by = 1)
1771
- decrement(attribute, by).update_attribute(attribute, self[attribute])
1772
- end
1773
-
1774
- # Assigns to +attribute+ the boolean opposite of <tt>attribute?</tt>. So
1775
- # if the predicate returns +true+ the attribute will become +false+. This
1776
- # method toggles directly the underlying value without calling any setter.
1777
- # Returns +self+.
1778
- def toggle(attribute)
1779
- self[attribute] = !send("#{attribute}?")
1780
- self
1781
- end
1782
-
1783
- # Wrapper around +toggle+ that saves the record. This method differs from
1784
- # its non-bang version in that it passes through the attribute setter.
1785
- # Saving is not subjected to validation checks. Returns +true+ if the
1786
- # record could be saved.
1787
- def toggle!(attribute)
1788
- toggle(attribute).update_attribute(attribute, self[attribute])
1789
- end
1790
-
1791
- # Reloads the attributes of this object from the database.
1792
- # The optional options argument is passed to find when reloading so you
1793
- # may do e.g. record.reload(:lock => true) to reload the same record with
1794
- # an exclusive row lock.
1795
- def reload(options = nil)
1796
- clear_aggregation_cache
1797
- clear_association_cache
1798
- @attributes.update(self.class.send(:with_exclusive_scope) { self.class.find(self.id, options) }.instance_variable_get('@attributes'))
1799
- @attributes_cache = {}
1800
- self
1801
- end
1802
-
1803
1532
  # Returns true if the given attribute is in the attributes hash
1804
1533
  def has_attribute?(attr_name)
1805
1534
  @attributes.has_key?(attr_name.to_s)
@@ -1845,8 +1574,7 @@ module ActiveRecord #:nodoc:
1845
1574
  # user.is_admin? # => true
1846
1575
  def attributes=(new_attributes, guard_protected_attributes = true)
1847
1576
  return if new_attributes.nil?
1848
- attributes = new_attributes.dup
1849
- attributes.stringify_keys!
1577
+ attributes = new_attributes.stringify_keys
1850
1578
 
1851
1579
  multi_parameter_attributes = []
1852
1580
  attributes = remove_attributes_protected_from_mass_assignment(attributes) if guard_protected_attributes
@@ -1978,40 +1706,6 @@ module ActiveRecord #:nodoc:
1978
1706
  end
1979
1707
 
1980
1708
  private
1981
- def create_or_update
1982
- raise ReadOnlyRecord if readonly?
1983
- result = new_record? ? create : update
1984
- result != false
1985
- end
1986
-
1987
- # Updates the associated record with values matching those of the instance attributes.
1988
- # Returns the number of affected rows.
1989
- def update(attribute_names = @attributes.keys)
1990
- attributes_with_values = arel_attributes_values(false, false, attribute_names)
1991
- return 0 if attributes_with_values.empty?
1992
- self.class.unscoped.where(self.class.arel_table[self.class.primary_key].eq(id)).arel.update(attributes_with_values)
1993
- end
1994
-
1995
- # Creates a record with values matching those of the instance attributes
1996
- # and returns its id.
1997
- def create
1998
- if self.id.nil? && connection.prefetch_primary_key?(self.class.table_name)
1999
- self.id = connection.next_sequence_value(self.class.sequence_name)
2000
- end
2001
-
2002
- attributes_values = arel_attributes_values
2003
-
2004
- new_id = if attributes_values.empty?
2005
- self.class.unscoped.insert connection.empty_insert_statement_value
2006
- else
2007
- self.class.unscoped.insert attributes_values
2008
- end
2009
-
2010
- self.id ||= new_id
2011
-
2012
- @new_record = false
2013
- id
2014
- end
2015
1709
 
2016
1710
  # Sets the attribute used for single table inheritance to this class name if this is not the ActiveRecord::Base descendant.
2017
1711
  # Considering the hierarchy Reply < Message < ActiveRecord::Base, this makes it possible to do Reply.new without having to
@@ -2094,18 +1788,7 @@ module ActiveRecord #:nodoc:
2094
1788
  # Interpolate custom SQL string in instance context.
2095
1789
  # Optional record argument is meant for custom insert_sql.
2096
1790
  def interpolate_sql(sql, record = nil)
2097
- instance_eval("%@#{sql.gsub('@', '\@')}@")
2098
- end
2099
-
2100
- # Initializes the attributes array with keys matching the columns from the linked table and
2101
- # the values matching the corresponding default value of that column, so
2102
- # that a new instance, or one populated from a passed-in Hash, still has all the attributes
2103
- # that instances loaded from the database would.
2104
- def attributes_from_column_definition
2105
- self.class.columns.inject({}) do |attributes, column|
2106
- attributes[column.name] = column.default unless column.name == self.class.primary_key
2107
- attributes
2108
- end
1791
+ instance_eval("%@#{sql.gsub('@', '\@')}@", __FILE__, __LINE__)
2109
1792
  end
2110
1793
 
2111
1794
  # Instantiates objects for all attribute classes that needs more than one constructor parameter. This is done
@@ -2223,12 +1906,14 @@ module ActiveRecord #:nodoc:
2223
1906
  end
2224
1907
 
2225
1908
  Base.class_eval do
1909
+ include ActiveRecord::Persistence
2226
1910
  extend ActiveModel::Naming
2227
1911
  extend QueryCache::ClassMethods
2228
1912
  extend ActiveSupport::Benchmarkable
2229
1913
 
2230
1914
  include ActiveModel::Conversion
2231
1915
  include Validations
1916
+ extend CounterCache
2232
1917
  include Locking::Optimistic, Locking::Pessimistic
2233
1918
  include AttributeMethods
2234
1919
  include AttributeMethods::Read, AttributeMethods::Write, AttributeMethods::BeforeTypeCast, AttributeMethods::Query