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.
- data/CHANGELOG +27 -0
- data/lib/active_record.rb +5 -1
- data/lib/active_record/aggregations.rb +1 -0
- data/lib/active_record/association_preload.rb +1 -1
- data/lib/active_record/associations.rb +88 -33
- data/lib/active_record/associations/association_collection.rb +12 -11
- data/lib/active_record/associations/association_proxy.rb +1 -1
- data/lib/active_record/attribute_methods.rb +10 -1
- data/lib/active_record/attribute_methods/dirty.rb +50 -50
- data/lib/active_record/attribute_methods/primary_key.rb +1 -1
- data/lib/active_record/autosave_association.rb +20 -5
- data/lib/active_record/base.rb +28 -343
- data/lib/active_record/callbacks.rb +23 -34
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +57 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +56 -0
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +11 -18
- data/lib/active_record/connection_adapters/abstract/quoting.rb +3 -7
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +61 -7
- data/lib/active_record/connection_adapters/abstract_adapter.rb +3 -1
- data/lib/active_record/connection_adapters/mysql_adapter.rb +22 -50
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +31 -143
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +6 -2
- data/lib/active_record/counter_cache.rb +105 -0
- data/lib/active_record/fixtures.rb +16 -15
- data/lib/active_record/locale/en.yml +2 -2
- data/lib/active_record/locking/optimistic.rb +37 -16
- data/lib/active_record/migration.rb +7 -3
- data/lib/active_record/named_scope.rb +1 -5
- data/lib/active_record/nested_attributes.rb +13 -2
- data/lib/active_record/observer.rb +19 -7
- data/lib/active_record/persistence.rb +230 -0
- data/lib/active_record/railtie.rb +17 -23
- data/lib/active_record/railties/databases.rake +3 -2
- data/lib/active_record/relation.rb +5 -2
- data/lib/active_record/relation/batches.rb +6 -1
- data/lib/active_record/relation/calculations.rb +12 -9
- data/lib/active_record/relation/finder_methods.rb +14 -10
- data/lib/active_record/relation/query_methods.rb +62 -44
- data/lib/active_record/relation/spawn_methods.rb +6 -1
- data/lib/active_record/schema_dumper.rb +3 -0
- data/lib/active_record/serializers/xml_serializer.rb +30 -56
- data/lib/active_record/session_store.rb +1 -1
- data/lib/active_record/timestamp.rb +22 -26
- data/lib/active_record/transactions.rb +168 -50
- data/lib/active_record/validations.rb +33 -49
- data/lib/active_record/version.rb +1 -1
- data/lib/rails/generators/active_record.rb +6 -9
- metadata +27 -10
@@ -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
|
199
|
+
def reload(options = nil)
|
200
200
|
@marked_for_destruction = false
|
201
|
-
|
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.
|
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)
|
data/lib/active_record/base.rb
CHANGED
@@ -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
|
-
#
|
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] +
|
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
|
-
|
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
|
-
|
1399
|
+
c.quote(nil)
|
1498
1400
|
else
|
1499
|
-
value.map { |v|
|
1401
|
+
value.map { |v| c.quote(v) }.join(',')
|
1500
1402
|
end
|
1501
1403
|
else
|
1502
|
-
|
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.
|
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
|