activerecord 3.0.0 → 3.0.3
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.
- data/CHANGELOG +42 -0
- data/examples/performance.rb +18 -1
- data/lib/active_record.rb +3 -3
- data/lib/active_record/aggregations.rb +2 -2
- data/lib/active_record/association_preload.rb +1 -1
- data/lib/active_record/associations.rb +59 -26
- data/lib/active_record/associations/association_collection.rb +28 -18
- data/lib/active_record/associations/association_proxy.rb +4 -4
- data/lib/active_record/associations/belongs_to_association.rb +3 -3
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +10 -13
- data/lib/active_record/associations/has_many_through_association.rb +2 -3
- data/lib/active_record/associations/has_one_association.rb +6 -6
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/attribute_methods/before_type_cast.rb +1 -4
- data/lib/active_record/attribute_methods/primary_key.rb +4 -3
- data/lib/active_record/autosave_association.rb +7 -7
- data/lib/active_record/base.rb +71 -47
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +6 -8
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +5 -9
- data/lib/active_record/connection_adapters/mysql_adapter.rb +7 -7
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +2 -2
- data/lib/active_record/dynamic_finder_match.rb +20 -17
- data/lib/active_record/dynamic_scope_match.rb +6 -15
- data/lib/active_record/fixtures.rb +3 -5
- data/lib/active_record/locking/optimistic.rb +1 -1
- data/lib/active_record/locking/pessimistic.rb +4 -4
- data/lib/active_record/nested_attributes.rb +17 -13
- data/lib/active_record/persistence.rb +7 -8
- data/lib/active_record/railties/databases.rake +7 -7
- data/lib/active_record/relation.rb +16 -18
- data/lib/active_record/relation/batches.rb +1 -1
- data/lib/active_record/relation/calculations.rb +37 -28
- data/lib/active_record/relation/finder_methods.rb +19 -19
- data/lib/active_record/relation/predicate_builder.rb +8 -1
- data/lib/active_record/relation/query_methods.rb +100 -75
- data/lib/active_record/relation/spawn_methods.rb +50 -39
- data/lib/active_record/serialization.rb +1 -1
- data/lib/active_record/session_store.rb +4 -4
- data/lib/active_record/transactions.rb +6 -6
- data/lib/active_record/validations.rb +1 -1
- data/lib/active_record/validations/uniqueness.rb +6 -1
- data/lib/active_record/version.rb +2 -2
- data/lib/rails/generators/active_record.rb +2 -10
- data/lib/rails/generators/active_record/migration.rb +15 -0
- metadata +15 -14
@@ -14,7 +14,7 @@ module ActiveRecord
|
|
14
14
|
counter_cache_name = @reflection.counter_cache_column
|
15
15
|
|
16
16
|
if record.nil?
|
17
|
-
if counter_cache_name &&
|
17
|
+
if counter_cache_name && @owner.persisted?
|
18
18
|
@reflection.klass.decrement_counter(counter_cache_name, previous_record_id) if @owner[@reflection.primary_key_name]
|
19
19
|
end
|
20
20
|
|
@@ -22,13 +22,13 @@ module ActiveRecord
|
|
22
22
|
else
|
23
23
|
raise_on_type_mismatch(record)
|
24
24
|
|
25
|
-
if counter_cache_name &&
|
25
|
+
if counter_cache_name && @owner.persisted? && record.id != @owner[@reflection.primary_key_name]
|
26
26
|
@reflection.klass.increment_counter(counter_cache_name, record.id)
|
27
27
|
@reflection.klass.decrement_counter(counter_cache_name, @owner[@reflection.primary_key_name]) if @owner[@reflection.primary_key_name]
|
28
28
|
end
|
29
29
|
|
30
30
|
@target = (AssociationProxy === record ? record.target : record)
|
31
|
-
@owner[@reflection.primary_key_name] = record_id(record)
|
31
|
+
@owner[@reflection.primary_key_name] = record_id(record) if record.persisted?
|
32
32
|
@updated = true
|
33
33
|
end
|
34
34
|
|
@@ -34,7 +34,7 @@ module ActiveRecord
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def insert_record(record, force = true, validate = true)
|
37
|
-
|
37
|
+
unless record.persisted?
|
38
38
|
if force
|
39
39
|
record.save!
|
40
40
|
else
|
@@ -49,23 +49,20 @@ module ActiveRecord
|
|
49
49
|
timestamps = record_timestamp_columns(record)
|
50
50
|
timezone = record.send(:current_time_from_proper_timezone) if timestamps.any?
|
51
51
|
|
52
|
-
attributes = columns.
|
52
|
+
attributes = Hash[columns.map do |column|
|
53
53
|
name = column.name
|
54
|
-
case name.to_s
|
54
|
+
value = case name.to_s
|
55
55
|
when @reflection.primary_key_name.to_s
|
56
|
-
|
56
|
+
@owner.id
|
57
57
|
when @reflection.association_foreign_key.to_s
|
58
|
-
|
58
|
+
record.id
|
59
59
|
when *timestamps
|
60
|
-
|
60
|
+
timezone
|
61
61
|
else
|
62
|
-
if record.has_attribute?(name)
|
63
|
-
value = @owner.send(:quote_value, record[name], column)
|
64
|
-
attrs[relation[name]] = value unless value.nil?
|
65
|
-
end
|
62
|
+
@owner.send(:quote_value, record[name], column) if record.has_attribute?(name)
|
66
63
|
end
|
67
|
-
|
68
|
-
end
|
64
|
+
[relation[name], value] unless value.nil?
|
65
|
+
end]
|
69
66
|
|
70
67
|
relation.insert(attributes)
|
71
68
|
end
|
@@ -79,7 +76,7 @@ module ActiveRecord
|
|
79
76
|
else
|
80
77
|
relation = Arel::Table.new(@reflection.options[:join_table])
|
81
78
|
relation.where(relation[@reflection.primary_key_name].eq(@owner.id).
|
82
|
-
and(relation[@reflection.association_foreign_key].in(records.map { |x| x.id }))
|
79
|
+
and(relation[@reflection.association_foreign_key].in(records.map { |x| x.id }.compact))
|
83
80
|
).delete
|
84
81
|
end
|
85
82
|
end
|
@@ -59,7 +59,7 @@ module ActiveRecord
|
|
59
59
|
end
|
60
60
|
|
61
61
|
def insert_record(record, force = true, validate = true)
|
62
|
-
|
62
|
+
unless record.persisted?
|
63
63
|
if force
|
64
64
|
record.save!
|
65
65
|
else
|
@@ -68,8 +68,7 @@ module ActiveRecord
|
|
68
68
|
end
|
69
69
|
|
70
70
|
through_association = @owner.send(@reflection.through_reflection.name)
|
71
|
-
|
72
|
-
through_association.proxy_target << through_record
|
71
|
+
through_association.create!(construct_join_attributes(record))
|
73
72
|
end
|
74
73
|
|
75
74
|
# TODO - add dependent option support
|
@@ -35,18 +35,18 @@ module ActiveRecord
|
|
35
35
|
if dependent? && !dont_save
|
36
36
|
case @reflection.options[:dependent]
|
37
37
|
when :delete
|
38
|
-
@target.delete
|
38
|
+
@target.delete if @target.persisted?
|
39
39
|
@owner.clear_association_cache
|
40
40
|
when :destroy
|
41
|
-
@target.destroy
|
41
|
+
@target.destroy if @target.persisted?
|
42
42
|
@owner.clear_association_cache
|
43
43
|
when :nullify
|
44
44
|
@target[@reflection.primary_key_name] = nil
|
45
|
-
@target.save
|
45
|
+
@target.save if @owner.persisted? && @target.persisted?
|
46
46
|
end
|
47
47
|
else
|
48
48
|
@target[@reflection.primary_key_name] = nil
|
49
|
-
@target.save
|
49
|
+
@target.save if @owner.persisted? && @target.persisted?
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
@@ -61,7 +61,7 @@ module ActiveRecord
|
|
61
61
|
set_inverse_instance(obj, @owner)
|
62
62
|
@loaded = true
|
63
63
|
|
64
|
-
unless
|
64
|
+
unless !@owner.persisted? or obj.nil? or dont_save
|
65
65
|
return (obj.save ? self : false)
|
66
66
|
else
|
67
67
|
return (obj.nil? ? nil : self)
|
@@ -120,7 +120,7 @@ module ActiveRecord
|
|
120
120
|
if replace_existing
|
121
121
|
replace(record, true)
|
122
122
|
else
|
123
|
-
record[@reflection.primary_key_name] = @owner.id
|
123
|
+
record[@reflection.primary_key_name] = @owner.id if @owner.persisted?
|
124
124
|
self.target = record
|
125
125
|
set_inverse_instance(record, @owner)
|
126
126
|
end
|
@@ -21,7 +21,7 @@ module ActiveRecord
|
|
21
21
|
if current_object
|
22
22
|
new_value ? current_object.update_attributes(construct_join_attributes(new_value)) : current_object.destroy
|
23
23
|
elsif new_value
|
24
|
-
|
24
|
+
unless @owner.persisted?
|
25
25
|
self.target = new_value
|
26
26
|
through_association = @owner.send(:association_instance_get, @reflection.through_reflection.name)
|
27
27
|
through_association.build(construct_join_attributes(new_value))
|
@@ -13,10 +13,7 @@ module ActiveRecord
|
|
13
13
|
|
14
14
|
# Returns a hash of attributes before typecasting and deserialization.
|
15
15
|
def attributes_before_type_cast
|
16
|
-
|
17
|
-
attrs[name] = read_attribute_before_type_cast(name)
|
18
|
-
attrs
|
19
|
-
end
|
16
|
+
Hash[attribute_names.map { |name| [name, read_attribute_before_type_cast(name)] }]
|
20
17
|
end
|
21
18
|
|
22
19
|
private
|
@@ -3,10 +3,11 @@ module ActiveRecord
|
|
3
3
|
module PrimaryKey
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
|
-
# Returns this record's primary key value wrapped in an Array
|
7
|
-
#
|
6
|
+
# Returns this record's primary key value wrapped in an Array or nil if
|
7
|
+
# the record is not persisted? or has just been destroyed.
|
8
8
|
def to_key
|
9
|
-
|
9
|
+
key = send(self.class.primary_key)
|
10
|
+
[key] if key
|
10
11
|
end
|
11
12
|
|
12
13
|
module ClassMethods
|
@@ -208,7 +208,7 @@ module ActiveRecord
|
|
208
208
|
# Returns whether or not this record has been changed in any way (including whether
|
209
209
|
# any of its nested autosave associations are likewise changed)
|
210
210
|
def changed_for_autosave?
|
211
|
-
|
211
|
+
!persisted? || changed? || marked_for_destruction? || nested_records_changed_for_autosave?
|
212
212
|
end
|
213
213
|
|
214
214
|
private
|
@@ -222,7 +222,7 @@ module ActiveRecord
|
|
222
222
|
elsif autosave
|
223
223
|
association.target.find_all { |record| record.changed_for_autosave? }
|
224
224
|
else
|
225
|
-
association.target.find_all { |record| record.
|
225
|
+
association.target.find_all { |record| !record.persisted? }
|
226
226
|
end
|
227
227
|
end
|
228
228
|
|
@@ -248,7 +248,7 @@ module ActiveRecord
|
|
248
248
|
# +reflection+.
|
249
249
|
def validate_collection_association(reflection)
|
250
250
|
if association = association_instance_get(reflection.name)
|
251
|
-
if records = associated_records_to_validate_or_save(association,
|
251
|
+
if records = associated_records_to_validate_or_save(association, !persisted?, reflection.options[:autosave])
|
252
252
|
records.each { |record| association_valid?(reflection, record) }
|
253
253
|
end
|
254
254
|
end
|
@@ -277,7 +277,7 @@ module ActiveRecord
|
|
277
277
|
# Is used as a before_save callback to check while saving a collection
|
278
278
|
# association whether or not the parent was a new record before saving.
|
279
279
|
def before_save_collection_association
|
280
|
-
@new_record_before_save =
|
280
|
+
@new_record_before_save = !persisted?
|
281
281
|
true
|
282
282
|
end
|
283
283
|
|
@@ -299,7 +299,7 @@ module ActiveRecord
|
|
299
299
|
|
300
300
|
if autosave && record.marked_for_destruction?
|
301
301
|
association.destroy(record)
|
302
|
-
elsif autosave != false && (@new_record_before_save || record.
|
302
|
+
elsif autosave != false && (@new_record_before_save || !record.persisted?)
|
303
303
|
if autosave
|
304
304
|
saved = association.send(:insert_record, record, false, false)
|
305
305
|
else
|
@@ -334,7 +334,7 @@ module ActiveRecord
|
|
334
334
|
association.destroy
|
335
335
|
else
|
336
336
|
key = reflection.options[:primary_key] ? send(reflection.options[:primary_key]) : id
|
337
|
-
if autosave != false && (
|
337
|
+
if autosave != false && (!persisted? || !association.persisted? || association[reflection.primary_key_name] != key || autosave)
|
338
338
|
association[reflection.primary_key_name] = key
|
339
339
|
saved = association.save(:validate => !autosave)
|
340
340
|
raise ActiveRecord::Rollback if !saved && autosave
|
@@ -354,7 +354,7 @@ module ActiveRecord
|
|
354
354
|
if autosave && association.marked_for_destruction?
|
355
355
|
association.destroy
|
356
356
|
elsif autosave != false
|
357
|
-
saved = association.save(:validate => !autosave) if association.
|
357
|
+
saved = association.save(:validate => !autosave) if !association.persisted? || autosave
|
358
358
|
|
359
359
|
if association.updated?
|
360
360
|
association_id = association.send(reflection.options[:primary_key] || :id)
|
data/lib/active_record/base.rb
CHANGED
@@ -205,7 +205,7 @@ module ActiveRecord #:nodoc:
|
|
205
205
|
#
|
206
206
|
# # No 'Winter' tag exists
|
207
207
|
# winter = Tag.find_or_initialize_by_name("Winter")
|
208
|
-
# winter.
|
208
|
+
# winter.persisted? # false
|
209
209
|
#
|
210
210
|
# To find by a subset of the attributes to be used for instantiating a new object, pass a hash instead of
|
211
211
|
# a list of parameters.
|
@@ -438,7 +438,7 @@ module ActiveRecord #:nodoc:
|
|
438
438
|
|
439
439
|
delegate :find, :first, :last, :all, :destroy, :destroy_all, :exists?, :delete, :delete_all, :update, :update_all, :to => :scoped
|
440
440
|
delegate :find_each, :find_in_batches, :to => :scoped
|
441
|
-
delegate :select, :group, :order, :reorder, :limit, :joins, :where, :preload, :eager_load, :includes, :from, :lock, :readonly, :having, :create_with, :to => :scoped
|
441
|
+
delegate :select, :group, :order, :reorder, :except, :limit, :offset, :joins, :where, :preload, :eager_load, :includes, :from, :lock, :readonly, :having, :create_with, :to => :scoped
|
442
442
|
delegate :count, :average, :minimum, :maximum, :sum, :calculate, :to => :scoped
|
443
443
|
|
444
444
|
# Executes a custom SQL query against your database and returns all the results. The results will
|
@@ -608,7 +608,7 @@ module ActiveRecord #:nodoc:
|
|
608
608
|
# Defines the column name for use with single table inheritance. Use
|
609
609
|
# <tt>set_inheritance_column</tt> to set a different value.
|
610
610
|
def inheritance_column
|
611
|
-
@inheritance_column ||= "type"
|
611
|
+
@inheritance_column ||= "type"
|
612
612
|
end
|
613
613
|
|
614
614
|
# Lazy-set the sequence name to the connection's default. This method
|
@@ -684,7 +684,7 @@ module ActiveRecord #:nodoc:
|
|
684
684
|
|
685
685
|
# Returns a hash of column objects for the table associated with this class.
|
686
686
|
def columns_hash
|
687
|
-
@columns_hash ||= columns.
|
687
|
+
@columns_hash ||= Hash[columns.map { |column| [column.name, column] }]
|
688
688
|
end
|
689
689
|
|
690
690
|
# Returns an array of column names as strings.
|
@@ -855,7 +855,7 @@ module ActiveRecord #:nodoc:
|
|
855
855
|
if self == ActiveRecord::Base
|
856
856
|
Arel::Table.engine
|
857
857
|
else
|
858
|
-
connection_handler.connection_pools[name] ?
|
858
|
+
connection_handler.connection_pools[name] ? self : superclass.arel_engine
|
859
859
|
end
|
860
860
|
end
|
861
861
|
end
|
@@ -890,6 +890,10 @@ module ActiveRecord #:nodoc:
|
|
890
890
|
Thread.current[key] = Thread.current[key].presence || self.default_scoping.dup
|
891
891
|
end
|
892
892
|
|
893
|
+
def before_remove_const #:nodoc:
|
894
|
+
reset_scoped_methods
|
895
|
+
end
|
896
|
+
|
893
897
|
private
|
894
898
|
|
895
899
|
def relation #:nodoc:
|
@@ -901,21 +905,9 @@ module ActiveRecord #:nodoc:
|
|
901
905
|
# single-table inheritance model that makes it possible to create
|
902
906
|
# objects of different types from the same table.
|
903
907
|
def instantiate(record)
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
object.instance_variable_set(:@attributes_cache, {})
|
908
|
-
object.instance_variable_set(:@new_record, false)
|
909
|
-
object.instance_variable_set(:@readonly, false)
|
910
|
-
object.instance_variable_set(:@destroyed, false)
|
911
|
-
object.instance_variable_set(:@marked_for_destruction, false)
|
912
|
-
object.instance_variable_set(:@previously_changed, {})
|
913
|
-
object.instance_variable_set(:@changed_attributes, {})
|
914
|
-
|
915
|
-
object.send(:_run_find_callbacks)
|
916
|
-
object.send(:_run_initialize_callbacks)
|
917
|
-
|
918
|
-
object
|
908
|
+
model = find_sti_class(record[inheritance_column]).allocate
|
909
|
+
model.init_with('attributes' => record)
|
910
|
+
model
|
919
911
|
end
|
920
912
|
|
921
913
|
def find_sti_class(type_name)
|
@@ -939,7 +931,7 @@ module ActiveRecord #:nodoc:
|
|
939
931
|
end
|
940
932
|
|
941
933
|
def construct_finder_arel(options = {}, scope = nil)
|
942
|
-
relation = options.is_a?(Hash) ? unscoped.apply_finder_options(options) :
|
934
|
+
relation = options.is_a?(Hash) ? unscoped.apply_finder_options(options) : options
|
943
935
|
relation = scope.merge(relation) if scope
|
944
936
|
relation
|
945
937
|
end
|
@@ -1039,8 +1031,9 @@ module ActiveRecord #:nodoc:
|
|
1039
1031
|
end
|
1040
1032
|
|
1041
1033
|
def all_attributes_exists?(attribute_names)
|
1042
|
-
|
1043
|
-
|
1034
|
+
expand_attribute_names_for_aggregates(attribute_names).all? { |name|
|
1035
|
+
column_methods_hash.include?(name.to_sym)
|
1036
|
+
}
|
1044
1037
|
end
|
1045
1038
|
|
1046
1039
|
protected
|
@@ -1096,9 +1089,9 @@ module ActiveRecord #:nodoc:
|
|
1096
1089
|
|
1097
1090
|
if method_scoping.is_a?(Hash)
|
1098
1091
|
# Dup first and second level of hash (method and params).
|
1099
|
-
method_scoping = method_scoping.
|
1100
|
-
|
1101
|
-
|
1092
|
+
method_scoping = method_scoping.dup
|
1093
|
+
method_scoping.each do |method, params|
|
1094
|
+
method_scoping[method] = params.dup unless params == true
|
1102
1095
|
end
|
1103
1096
|
|
1104
1097
|
method_scoping.assert_valid_keys([ :find, :create ])
|
@@ -1167,6 +1160,7 @@ MSG
|
|
1167
1160
|
# Article.new.published # => true
|
1168
1161
|
# Article.create.published # => true
|
1169
1162
|
def default_scope(options = {})
|
1163
|
+
reset_scoped_methods
|
1170
1164
|
self.default_scoping << construct_finder_arel(options, default_scoping.pop)
|
1171
1165
|
end
|
1172
1166
|
|
@@ -1174,6 +1168,10 @@ MSG
|
|
1174
1168
|
scoped_methods.last
|
1175
1169
|
end
|
1176
1170
|
|
1171
|
+
def reset_scoped_methods #:nodoc:
|
1172
|
+
Thread.current[:"#{self}_scoped_methods"] = nil
|
1173
|
+
end
|
1174
|
+
|
1177
1175
|
# Returns the class type of the record using the current module as a prefix. So descendants of
|
1178
1176
|
# MyApp::Business::Account would appear as MyApp::Business::AccountSubclass.
|
1179
1177
|
def compute_type(type_name)
|
@@ -1395,7 +1393,7 @@ MSG
|
|
1395
1393
|
def initialize(attributes = nil)
|
1396
1394
|
@attributes = attributes_from_column_definition
|
1397
1395
|
@attributes_cache = {}
|
1398
|
-
@
|
1396
|
+
@persisted = false
|
1399
1397
|
@readonly = false
|
1400
1398
|
@destroyed = false
|
1401
1399
|
@marked_for_destruction = false
|
@@ -1404,10 +1402,7 @@ MSG
|
|
1404
1402
|
|
1405
1403
|
ensure_proper_type
|
1406
1404
|
|
1407
|
-
|
1408
|
-
create_with = scope.scope_for_create
|
1409
|
-
create_with.each { |att,value| self.send("#{att}=", value) } if create_with
|
1410
|
-
end
|
1405
|
+
populate_with_current_scope_attributes
|
1411
1406
|
self.attributes = attributes unless attributes.nil?
|
1412
1407
|
|
1413
1408
|
result = yield self if block_given?
|
@@ -1433,13 +1428,29 @@ MSG
|
|
1433
1428
|
clear_aggregation_cache
|
1434
1429
|
clear_association_cache
|
1435
1430
|
@attributes_cache = {}
|
1436
|
-
@
|
1431
|
+
@persisted = false
|
1437
1432
|
ensure_proper_type
|
1438
1433
|
|
1439
|
-
|
1440
|
-
|
1441
|
-
|
1442
|
-
|
1434
|
+
populate_with_current_scope_attributes
|
1435
|
+
end
|
1436
|
+
|
1437
|
+
# Initialize an empty model object from +coder+. +coder+ must contain
|
1438
|
+
# the attributes necessary for initializing an empty model object. For
|
1439
|
+
# example:
|
1440
|
+
#
|
1441
|
+
# class Post < ActiveRecord::Base
|
1442
|
+
# end
|
1443
|
+
#
|
1444
|
+
# post = Post.allocate
|
1445
|
+
# post.init_with('attributes' => { 'title' => 'hello world' })
|
1446
|
+
# post.title # => 'hello world'
|
1447
|
+
def init_with(coder)
|
1448
|
+
@attributes = coder['attributes']
|
1449
|
+
@attributes_cache, @previously_changed, @changed_attributes = {}, {}, {}
|
1450
|
+
@readonly = @destroyed = @marked_for_destruction = false
|
1451
|
+
@persisted = true
|
1452
|
+
_run_find_callbacks
|
1453
|
+
_run_initialize_callbacks
|
1443
1454
|
end
|
1444
1455
|
|
1445
1456
|
# Returns a String, which Action Pack uses for constructing an URL to this
|
@@ -1478,7 +1489,7 @@ MSG
|
|
1478
1489
|
# Person.find(5).cache_key # => "people/5-20071224150000" (updated_at available)
|
1479
1490
|
def cache_key
|
1480
1491
|
case
|
1481
|
-
when
|
1492
|
+
when !persisted?
|
1482
1493
|
"#{self.class.model_name.cache_key}/new"
|
1483
1494
|
when timestamp = self[:updated_at]
|
1484
1495
|
"#{self.class.model_name.cache_key}/#{id}-#{timestamp.to_s(:number)}"
|
@@ -1596,11 +1607,20 @@ MSG
|
|
1596
1607
|
self.class.columns_hash[name.to_s]
|
1597
1608
|
end
|
1598
1609
|
|
1599
|
-
# Returns true if
|
1610
|
+
# Returns true if +comparison_object+ is the same exact object, or +comparison_object+
|
1611
|
+
# is of the same type and +self+ has an ID and it is equal to +comparison_object.id+.
|
1612
|
+
#
|
1613
|
+
# Note that new records are different from any other record by definition, unless the
|
1614
|
+
# other record is the receiver itself. Besides, if you fetch existing records with
|
1615
|
+
# +select+ and leave the ID out, you're on your own, this predicate will return false.
|
1616
|
+
#
|
1617
|
+
# Note also that destroying a record preserves its ID in the model instance, so deleted
|
1618
|
+
# models are still comparable.
|
1600
1619
|
def ==(comparison_object)
|
1601
1620
|
comparison_object.equal?(self) ||
|
1602
|
-
|
1603
|
-
|
1621
|
+
comparison_object.instance_of?(self.class) &&
|
1622
|
+
id.present? &&
|
1623
|
+
comparison_object.id == id
|
1604
1624
|
end
|
1605
1625
|
|
1606
1626
|
# Delegates to ==
|
@@ -1645,7 +1665,7 @@ MSG
|
|
1645
1665
|
# Returns the contents of the record as a nicely formatted string.
|
1646
1666
|
def inspect
|
1647
1667
|
attributes_as_nice_string = self.class.column_names.collect { |name|
|
1648
|
-
if has_attribute?(name) ||
|
1668
|
+
if has_attribute?(name) || !persisted?
|
1649
1669
|
"#{name}: #{attribute_for_inspect(name)}"
|
1650
1670
|
end
|
1651
1671
|
}.compact.join(", ")
|
@@ -1697,8 +1717,8 @@ MSG
|
|
1697
1717
|
if include_readonly_attributes || (!include_readonly_attributes && !self.class.readonly_attributes.include?(name))
|
1698
1718
|
value = read_attribute(name)
|
1699
1719
|
|
1700
|
-
if value &&
|
1701
|
-
value = value
|
1720
|
+
if value && self.class.serialized_attributes.key?(name)
|
1721
|
+
value = YAML.dump value
|
1702
1722
|
end
|
1703
1723
|
attrs[self.class.arel_table[name]] = value
|
1704
1724
|
end
|
@@ -1805,10 +1825,7 @@ MSG
|
|
1805
1825
|
end
|
1806
1826
|
|
1807
1827
|
def quote_columns(quoter, hash)
|
1808
|
-
hash.
|
1809
|
-
quoted[quoter.quote_column_name(name)] = value
|
1810
|
-
quoted
|
1811
|
-
end
|
1828
|
+
Hash[hash.map { |name, value| [quoter.quote_column_name(name), value] }]
|
1812
1829
|
end
|
1813
1830
|
|
1814
1831
|
def quoted_comma_pair_list(quoter, hash)
|
@@ -1831,6 +1848,13 @@ MSG
|
|
1831
1848
|
return string unless string.is_a?(String) && string =~ /^---/
|
1832
1849
|
YAML::load(string) rescue string
|
1833
1850
|
end
|
1851
|
+
|
1852
|
+
def populate_with_current_scope_attributes
|
1853
|
+
if scope = self.class.send(:current_scoped_methods)
|
1854
|
+
create_with = scope.scope_for_create
|
1855
|
+
create_with.each { |att,value| self.respond_to?(:"#{att}=") && self.send("#{att}=", value) } if create_with
|
1856
|
+
end
|
1857
|
+
end
|
1834
1858
|
end
|
1835
1859
|
|
1836
1860
|
Base.class_eval do
|