composite_primary_keys 3.1.11 → 4.0.0.beta1
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.
- data/History.txt +6 -8
- data/lib/composite_primary_keys.rb +53 -36
- data/lib/composite_primary_keys/associations/association.rb +23 -0
- data/lib/composite_primary_keys/associations/association_scope.rb +67 -0
- data/lib/composite_primary_keys/associations/has_and_belongs_to_many_association.rb +31 -121
- data/lib/composite_primary_keys/associations/has_many_association.rb +27 -66
- data/lib/composite_primary_keys/associations/join_dependency/join_association.rb +22 -0
- data/lib/composite_primary_keys/associations/join_dependency/join_part.rb +39 -0
- data/lib/composite_primary_keys/associations/preloader/association.rb +61 -0
- data/lib/composite_primary_keys/associations/preloader/belongs_to.rb +13 -0
- data/lib/composite_primary_keys/associations/preloader/has_and_belongs_to_many.rb +46 -0
- data/lib/composite_primary_keys/attribute_methods/dirty.rb +30 -0
- data/lib/composite_primary_keys/attribute_methods/read.rb +88 -0
- data/lib/composite_primary_keys/attribute_methods/write.rb +33 -0
- data/lib/composite_primary_keys/base.rb +18 -70
- data/lib/composite_primary_keys/composite_predicates.rb +53 -0
- data/lib/composite_primary_keys/connection_adapters/abstract_adapter.rb +6 -4
- data/lib/composite_primary_keys/connection_adapters/postgresql_adapter.rb +19 -41
- data/lib/composite_primary_keys/fixtures.rb +19 -6
- data/lib/composite_primary_keys/persistence.rb +32 -13
- data/lib/composite_primary_keys/relation.rb +23 -16
- data/lib/composite_primary_keys/relation/calculations.rb +48 -0
- data/lib/composite_primary_keys/relation/finder_methods.rb +117 -0
- data/lib/composite_primary_keys/relation/query_methods.rb +24 -0
- data/lib/composite_primary_keys/validations/uniqueness.rb +19 -23
- data/lib/composite_primary_keys/version.rb +5 -5
- data/test/connections/native_mysql/connection.rb +1 -1
- data/test/fixtures/articles.yml +1 -0
- data/test/fixtures/products.yml +2 -4
- data/test/fixtures/readings.yml +1 -0
- data/test/fixtures/suburbs.yml +1 -4
- data/test/fixtures/users.yml +1 -0
- data/test/test_associations.rb +61 -63
- data/test/test_attributes.rb +16 -21
- data/test/test_create.rb +3 -3
- data/test/test_delete.rb +87 -84
- data/test/{test_clone.rb → test_dup.rb} +8 -5
- data/test/test_exists.rb +22 -10
- data/test/test_habtm.rb +0 -74
- data/test/test_ids.rb +2 -1
- data/test/test_miscellaneous.rb +2 -2
- data/test/test_polymorphic.rb +1 -1
- data/test/test_suite.rb +1 -1
- data/test/test_update.rb +3 -3
- metadata +76 -75
- data/lib/composite_primary_keys/association_preload.rb +0 -158
- data/lib/composite_primary_keys/associations.rb +0 -155
- data/lib/composite_primary_keys/associations/association_proxy.rb +0 -33
- data/lib/composite_primary_keys/associations/has_one_association.rb +0 -27
- data/lib/composite_primary_keys/associations/through_association_scope.rb +0 -103
- data/lib/composite_primary_keys/attribute_methods.rb +0 -84
- data/lib/composite_primary_keys/calculations.rb +0 -31
- data/lib/composite_primary_keys/connection_adapters/ibm_db_adapter.rb +0 -21
- data/lib/composite_primary_keys/connection_adapters/oracle_adapter.rb +0 -15
- data/lib/composite_primary_keys/connection_adapters/oracle_enhanced_adapter.rb +0 -17
- data/lib/composite_primary_keys/connection_adapters/sqlite3_adapter.rb +0 -15
- data/lib/composite_primary_keys/finder_methods.rb +0 -123
- data/lib/composite_primary_keys/primary_key.rb +0 -19
- data/lib/composite_primary_keys/query_methods.rb +0 -24
- data/lib/composite_primary_keys/read.rb +0 -25
- data/lib/composite_primary_keys/reflection.rb +0 -37
- data/lib/composite_primary_keys/write.rb +0 -18
@@ -0,0 +1,22 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Associations
|
3
|
+
class JoinDependency
|
4
|
+
class JoinAssociation
|
5
|
+
def build_constraint(reflection, table, key, foreign_table, foreign_key)
|
6
|
+
# CPK
|
7
|
+
# constraint = table[key].eq(foreign_table[foreign_key])
|
8
|
+
constraint = cpk_join_predicate(table, key, foreign_table, foreign_key)
|
9
|
+
|
10
|
+
if reflection.klass.finder_needs_type_condition?
|
11
|
+
constraint = table.create_and([
|
12
|
+
constraint,
|
13
|
+
reflection.klass.send(:type_condition, table)
|
14
|
+
])
|
15
|
+
end
|
16
|
+
|
17
|
+
constraint
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Associations
|
3
|
+
class JoinDependency
|
4
|
+
class JoinPart
|
5
|
+
def aliased_primary_key
|
6
|
+
# CPK
|
7
|
+
# "#{aliased_prefix}_r0"
|
8
|
+
|
9
|
+
active_record.composite? ?
|
10
|
+
primary_key.inject([]) {|aliased_keys, key| aliased_keys << "#{ aliased_prefix }_r#{aliased_keys.length}"} :
|
11
|
+
"#{ aliased_prefix }_r0"
|
12
|
+
end
|
13
|
+
|
14
|
+
def record_id(row)
|
15
|
+
# CPK
|
16
|
+
# row[aliased_primary_key]
|
17
|
+
active_record.composite? ?
|
18
|
+
aliased_primary_key.map {|key| row[key]}.to_composite_keys :
|
19
|
+
row[aliased_primary_key]
|
20
|
+
end
|
21
|
+
|
22
|
+
def column_names_with_alias
|
23
|
+
unless @column_names_with_alias
|
24
|
+
@column_names_with_alias = []
|
25
|
+
|
26
|
+
# CPK
|
27
|
+
#([primary_key] + (column_names - [primary_key])).each_with_index do |column_name, i|
|
28
|
+
keys = active_record.composite? ? primary_key.map(&:to_s) : [primary_key]
|
29
|
+
|
30
|
+
(keys + (column_names - keys)).each_with_index do |column_name, i|
|
31
|
+
@column_names_with_alias << [column_name, "#{aliased_prefix}_r#{i}"]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
@column_names_with_alias
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Associations
|
3
|
+
class Preloader
|
4
|
+
class Association
|
5
|
+
def records_for(ids)
|
6
|
+
# CPK
|
7
|
+
# scoped.where(association_key.in(ids))
|
8
|
+
predicate = cpk_in_predicate(table, reflection.foreign_key, ids)
|
9
|
+
scoped.where(predicate)
|
10
|
+
end
|
11
|
+
|
12
|
+
def associated_records_by_owner
|
13
|
+
# CPK
|
14
|
+
# owner_keys = owners.map { |owner| owner[owner_key_name] }.compact.uniq
|
15
|
+
owner_keys = owners.map do |owner|
|
16
|
+
Array(owner_key_name).map do |owner_key|
|
17
|
+
owner[owner_key]
|
18
|
+
end
|
19
|
+
end.compact.uniq
|
20
|
+
|
21
|
+
if klass.nil? || owner_keys.empty?
|
22
|
+
records = []
|
23
|
+
else
|
24
|
+
# Some databases impose a limit on the number of ids in a list (in Oracle it's 1000)
|
25
|
+
# Make several smaller queries if necessary or make one query if the adapter supports it
|
26
|
+
sliced = owner_keys.each_slice(model.connection.in_clause_length || owner_keys.size)
|
27
|
+
records = sliced.map { |slice| records_for(slice) }.flatten
|
28
|
+
end
|
29
|
+
|
30
|
+
# Each record may have multiple owners, and vice-versa
|
31
|
+
records_by_owner = Hash[owners.map { |owner| [owner, []] }]
|
32
|
+
records.each do |record|
|
33
|
+
# CPK
|
34
|
+
# owner_key = record[association_key_name].to_s
|
35
|
+
owner_key = Array(association_key_name).map do |key_name|
|
36
|
+
record[key_name]
|
37
|
+
end.join(CompositePrimaryKeys::ID_SEP)
|
38
|
+
|
39
|
+
owners_by_key[owner_key].each do |owner|
|
40
|
+
records_by_owner[owner] << record
|
41
|
+
end
|
42
|
+
end
|
43
|
+
records_by_owner
|
44
|
+
end
|
45
|
+
|
46
|
+
def owners_by_key
|
47
|
+
@owners_by_key ||= owners.group_by do |owner|
|
48
|
+
# CPK
|
49
|
+
# key = owner[owner_key_name]
|
50
|
+
key = Array(owner_key_name).map do |key_name|
|
51
|
+
owner[key_name]
|
52
|
+
end
|
53
|
+
# CPK
|
54
|
+
# key && key.to_s
|
55
|
+
key && key.join(CompositePrimaryKeys::ID_SEP)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Associations
|
3
|
+
class Preloader
|
4
|
+
class HasAndBelongsToMany
|
5
|
+
def records_for(ids)
|
6
|
+
# CPK
|
7
|
+
#scope = super
|
8
|
+
predicate = cpk_in_predicate(join_table, reflection.foreign_key, ids)
|
9
|
+
scope = scoped.where(predicate)
|
10
|
+
|
11
|
+
klass.connection.select_all(scope.arel.to_sql, 'SQL', scope.bind_values)
|
12
|
+
end
|
13
|
+
|
14
|
+
def join
|
15
|
+
# CPK
|
16
|
+
#condition = table[reflection.association_primary_key].eq(
|
17
|
+
# join_table[reflection.association_foreign_key])
|
18
|
+
condition = cpk_join_predicate(table, reflection.association_primary_key,
|
19
|
+
join_table, reflection.association_foreign_key)
|
20
|
+
|
21
|
+
table.create_join(join_table, table.create_on(condition))
|
22
|
+
end
|
23
|
+
|
24
|
+
def association_key_alias(field)
|
25
|
+
"ar_association_key_name_#{field.to_s}"
|
26
|
+
end
|
27
|
+
|
28
|
+
def join_select
|
29
|
+
# CPK
|
30
|
+
# association_key.as(Arel.sql(association_key_name))
|
31
|
+
Array(reflection.foreign_key).map do |key|
|
32
|
+
join_table[key].as(Arel.sql(association_key_alias(key)))
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def association_key_name
|
37
|
+
# CPK
|
38
|
+
# 'ar_association_key_name'
|
39
|
+
Array(reflection.foreign_key).map do |key|
|
40
|
+
association_key_alias(key)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module AttributeMethods
|
3
|
+
module Dirty
|
4
|
+
def write_attribute(attr, value)
|
5
|
+
# CPK
|
6
|
+
# attr = attr.to_s
|
7
|
+
attr = attr.to_s unless self.composite?
|
8
|
+
|
9
|
+
# The attribute already has an unsaved change.
|
10
|
+
if attribute_changed?(attr)
|
11
|
+
old = @changed_attributes[attr]
|
12
|
+
@changed_attributes.delete(attr) unless field_changed?(attr, old, value)
|
13
|
+
else
|
14
|
+
old = clone_attribute_value(:read_attribute, attr)
|
15
|
+
# Save Time objects as TimeWithZone if time_zone_aware_attributes == true
|
16
|
+
old = old.in_time_zone if clone_with_time_zone_conversion_attribute?(attr, old)
|
17
|
+
@changed_attributes[attr] = old if field_changed?(attr, old, value)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Carry on.
|
21
|
+
super(attr, value)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
ActiveRecord::Base.class_eval do
|
28
|
+
alias :[]= :write_attribute
|
29
|
+
public :[]=
|
30
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module AttributeMethods
|
3
|
+
module Read
|
4
|
+
module ClassMethods
|
5
|
+
def define_read_method(method_name, attr_name, column)
|
6
|
+
cast_code = column.type_cast_code('v')
|
7
|
+
# CPK - this is a really horrid hack, needed to get
|
8
|
+
# right class namespace :(
|
9
|
+
if cast_code.match(/^ActiveRecord/)
|
10
|
+
cast_code = "::#{cast_code}"
|
11
|
+
end
|
12
|
+
|
13
|
+
access_code = "(v=@attributes['#{attr_name}']) && #{cast_code}"
|
14
|
+
|
15
|
+
# CPK
|
16
|
+
# unless attr_name.to_s == self.primary_key.to_s
|
17
|
+
# access_code.insert(0, "missing_attribute('#{attr_name}', caller) unless @attributes.has_key?('#{attr_name}'); ")
|
18
|
+
# end
|
19
|
+
primary_keys = Array(self.primary_key)
|
20
|
+
|
21
|
+
unless primary_keys.include?(attr_name.to_s)
|
22
|
+
access_code = access_code.insert(0, "missing_attribute('#{attr_name}', caller) unless @attributes.has_key?('#{attr_name}'); ")
|
23
|
+
end
|
24
|
+
|
25
|
+
if cache_attribute?(attr_name)
|
26
|
+
access_code = "@attributes_cache['#{attr_name}'] ||= (#{access_code})"
|
27
|
+
end
|
28
|
+
|
29
|
+
# Where possible, generate the method by evalling a string, as this will result in
|
30
|
+
# faster accesses because it avoids the block eval and then string eval incurred
|
31
|
+
# by the second branch.
|
32
|
+
#
|
33
|
+
# The second, slower, branch is necessary to support instances where the database
|
34
|
+
# returns columns with extra stuff in (like 'my_column(omg)').
|
35
|
+
if method_name =~ ActiveModel::AttributeMethods::COMPILABLE_REGEXP
|
36
|
+
generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__
|
37
|
+
def _#{method_name}
|
38
|
+
#{access_code}
|
39
|
+
end
|
40
|
+
|
41
|
+
alias #{method_name} _#{method_name}
|
42
|
+
STR
|
43
|
+
else
|
44
|
+
generated_attribute_methods.module_eval do
|
45
|
+
define_method("_#{method_name}") { eval(access_code) }
|
46
|
+
alias_method(method_name, "_#{method_name}")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def read_attribute(attr_name)
|
53
|
+
# CPK
|
54
|
+
if attr_name.kind_of?(Array)
|
55
|
+
attr_name.map {|name| read_attribute(name)}.to_composite_keys
|
56
|
+
elsif respond_to? "_#{attr_name}"
|
57
|
+
send "_#{attr_name}" if @attributes.has_key?(attr_name.to_s)
|
58
|
+
else
|
59
|
+
_read_attribute attr_name
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
def _read_attribute(attr_name)
|
65
|
+
attr_name = attr_name.to_s
|
66
|
+
# CPK
|
67
|
+
# attr_name = self.class.primary_key if attr_name == 'id'
|
68
|
+
attr_name = self.class.primary_key if (attr_name == 'id' and !self.composite?)
|
69
|
+
value = @attributes[attr_name]
|
70
|
+
unless value.nil?
|
71
|
+
if column = column_for_attribute(attr_name)
|
72
|
+
if unserializable_attribute?(attr_name, column)
|
73
|
+
unserialize_attribute(attr_name)
|
74
|
+
else
|
75
|
+
column.type_cast(value)
|
76
|
+
end
|
77
|
+
else
|
78
|
+
value
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
ActiveRecord::Base.class_eval do
|
87
|
+
alias :[] :read_attribute
|
88
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module AttributeMethods
|
3
|
+
module Write
|
4
|
+
def write_attribute(attr_name, value)
|
5
|
+
# CPK
|
6
|
+
if attr_name.kind_of?(Array)
|
7
|
+
unless value.length == attr_name.length
|
8
|
+
raise "Number of attr_names and values do not match"
|
9
|
+
end
|
10
|
+
[attr_name, value].transpose.map {|name,val| write_attribute(name, val)}
|
11
|
+
value
|
12
|
+
else
|
13
|
+
attr_name = attr_name.to_s
|
14
|
+
# CPK
|
15
|
+
# attr_name = self.class.primary_key if attr_name == 'id'
|
16
|
+
attr_name = self.class.primary_key if (attr_name == 'id' and !self.composite?)
|
17
|
+
@attributes_cache.delete(attr_name)
|
18
|
+
if (column = column_for_attribute(attr_name)) && column.number?
|
19
|
+
@attributes[attr_name] = convert_number_column_value(value)
|
20
|
+
else
|
21
|
+
@attributes[attr_name] = value
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
#ActiveRecord::Base.class_eval do
|
30
|
+
# alias :[]= :write_attribute
|
31
|
+
# alias :raw_write_attribute :write_attribute
|
32
|
+
# public :[]=
|
33
|
+
#end
|
@@ -16,12 +16,11 @@ module ActiveRecord
|
|
16
16
|
end
|
17
17
|
|
18
18
|
cattr_accessor :primary_keys
|
19
|
-
self.primary_keys = keys.map { |k| k.to_sym }
|
19
|
+
self.primary_keys = keys.map { |k| k.to_sym }.to_composite_keys
|
20
20
|
|
21
21
|
class_eval <<-EOV
|
22
|
-
extend
|
22
|
+
extend CompositeClassMethods
|
23
23
|
include CompositeInstanceMethods
|
24
|
-
include CompositePrimaryKeys::ActiveRecord::AssociationPreload
|
25
24
|
EOV
|
26
25
|
end
|
27
26
|
|
@@ -34,38 +33,6 @@ module ActiveRecord
|
|
34
33
|
self.class.composite?
|
35
34
|
end
|
36
35
|
|
37
|
-
def [](attr_name)
|
38
|
-
# CPK
|
39
|
-
if attr_name.is_a?(String) and attr_name != attr_name.split(CompositePrimaryKeys::ID_SEP).first
|
40
|
-
attr_name = attr_name.split(CompositePrimaryKeys::ID_SEP)
|
41
|
-
end
|
42
|
-
|
43
|
-
# CPK
|
44
|
-
if attr_name.is_a?(Array)
|
45
|
-
values = attr_name.map {|name| read_attribute(name)}
|
46
|
-
CompositePrimaryKeys::CompositeKeys.new(values)
|
47
|
-
else
|
48
|
-
read_attribute(attr_name)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def []=(attr_name, value)
|
53
|
-
# CPK
|
54
|
-
if attr_name.is_a?(String) and attr_name != attr_name.split(CompositePrimaryKeys::ID_SEP).first
|
55
|
-
attr_name = attr_name.split(CompositePrimaryKeys::ID_SEP)
|
56
|
-
end
|
57
|
-
|
58
|
-
if attr_name.is_a? Array
|
59
|
-
unless value.length == attr_name.length
|
60
|
-
raise "Number of attr_names and values do not match"
|
61
|
-
end
|
62
|
-
[attr_name, value].transpose.map {|name,val| write_attribute(name, val)}
|
63
|
-
value
|
64
|
-
else
|
65
|
-
write_attribute(attr_name, value)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
36
|
module CompositeClassMethods
|
70
37
|
def primary_key
|
71
38
|
primary_keys
|
@@ -84,20 +51,6 @@ module ActiveRecord
|
|
84
51
|
def ids_to_s(many_ids, id_sep = CompositePrimaryKeys::ID_SEP, list_sep = ',', left_bracket = '(', right_bracket = ')')
|
85
52
|
many_ids.map {|ids| "#{left_bracket}#{CompositePrimaryKeys::CompositeKeys.new(ids)}#{right_bracket}"}.join(list_sep)
|
86
53
|
end
|
87
|
-
|
88
|
-
def relation #:nodoc:
|
89
|
-
@relation ||= begin
|
90
|
-
result = Relation.new(self, arel_table)
|
91
|
-
# CPK
|
92
|
-
class << result
|
93
|
-
include CompositePrimaryKeys::ActiveRecord::FinderMethods::InstanceMethods
|
94
|
-
include CompositePrimaryKeys::ActiveRecord::Relation::InstanceMethods
|
95
|
-
end
|
96
|
-
result
|
97
|
-
end
|
98
|
-
|
99
|
-
finder_needs_type_condition? ? @relation.where(type_condition) : @relation
|
100
|
-
end
|
101
54
|
end
|
102
55
|
|
103
56
|
module CompositeInstanceMethods
|
@@ -143,35 +96,30 @@ module ActiveRecord
|
|
143
96
|
ids.is_a?(Array) ? super(comparison_object) && ids.all? {|id| id.present?} : super(comparison_object)
|
144
97
|
end
|
145
98
|
|
146
|
-
|
147
|
-
# as it copies the object's attributes only, not its associations. The extent of a "deep" clone is
|
148
|
-
# application specific and is therefore left to the application to implement according to its need.
|
149
|
-
def initialize_copy(other)
|
150
|
-
# Think the assertion which fails if the after_initialize callback goes at the end of the method is wrong. The
|
151
|
-
# deleted clone method called new which therefore called the after_initialize callback. It then went on to copy
|
152
|
-
# over the attributes. But if it's copying the attributes afterwards then it hasn't finished initializing right?
|
153
|
-
# For example in the test suite the topic model's after_initialize method sets the author_email_address to
|
154
|
-
# test@test.com. I would have thought this would mean that all cloned models would have an author email address
|
155
|
-
# of test@test.com. However the test_clone test method seems to test that this is not the case. As a result the
|
156
|
-
# after_initialize callback has to be run *before* the copying of the atrributes rather than afterwards in order
|
157
|
-
# for all tests to pass. This makes no sense to me.
|
158
|
-
callback(:after_initialize) if respond_to_without_attributes?(:after_initialize)
|
99
|
+
def initialize_dup(other)
|
159
100
|
cloned_attributes = other.clone_attributes(:read_attribute_before_type_cast)
|
160
101
|
# CPK
|
161
102
|
#cloned_attributes.delete(self.class.primary_key)
|
162
103
|
self.class.primary_key.each {|key| cloned_attributes.delete(key.to_s)}
|
163
104
|
|
164
105
|
@attributes = cloned_attributes
|
165
|
-
clear_aggregation_cache
|
166
|
-
@attributes_cache = {}
|
167
|
-
@new_record = true
|
168
|
-
ensure_proper_type
|
169
106
|
|
170
|
-
if
|
171
|
-
|
172
|
-
|
107
|
+
_run_after_initialize_callbacks if respond_to?(:_run_after_initialize_callbacks)
|
108
|
+
|
109
|
+
@changed_attributes = {}
|
110
|
+
attributes_from_column_definition.each do |attr, orig_value|
|
111
|
+
@changed_attributes[attr] = orig_value if field_changed?(attr, orig_value, @attributes[attr])
|
173
112
|
end
|
113
|
+
|
114
|
+
@aggregation_cache = {}
|
115
|
+
@association_cache = {}
|
116
|
+
@attributes_cache = {}
|
117
|
+
@new_record = true
|
118
|
+
|
119
|
+
ensure_proper_type
|
120
|
+
populate_with_current_scope_attributes
|
121
|
+
clear_timestamp_attributes
|
174
122
|
end
|
175
123
|
end
|
176
124
|
end
|
177
|
-
end
|
125
|
+
end
|