composite_primary_keys 7.0.13 → 7.0.14
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.
- checksums.yaml +4 -4
- data/History.rdoc +615 -608
- data/lib/composite_primary_keys.rb +110 -110
- data/lib/composite_primary_keys/associations/association.rb +23 -23
- data/lib/composite_primary_keys/associations/association_scope.rb +77 -77
- data/lib/composite_primary_keys/associations/has_and_belongs_to_many_association.rb +59 -59
- data/lib/composite_primary_keys/associations/has_many_association.rb +56 -56
- data/lib/composite_primary_keys/associations/join_dependency.rb +89 -89
- data/lib/composite_primary_keys/associations/join_dependency/join_part.rb +38 -38
- data/lib/composite_primary_keys/associations/preloader/association.rb +78 -78
- data/lib/composite_primary_keys/associations/preloader/has_and_belongs_to_many.rb +46 -46
- data/lib/composite_primary_keys/attribute_methods/dirty.rb +26 -26
- data/lib/composite_primary_keys/attribute_methods/read.rb +34 -34
- data/lib/composite_primary_keys/attribute_methods/write.rb +36 -36
- data/lib/composite_primary_keys/base.rb +0 -6
- data/lib/composite_primary_keys/composite_arrays.rb +30 -30
- data/lib/composite_primary_keys/connection_adapters/abstract/connection_specification_changes.rb +4 -2
- data/lib/composite_primary_keys/connection_adapters/sqlserver_adapter.rb +17 -0
- data/lib/composite_primary_keys/core.rb +47 -47
- data/lib/composite_primary_keys/persistence.rb +60 -60
- data/lib/composite_primary_keys/relation.rb +56 -56
- data/lib/composite_primary_keys/relation/calculations.rb +75 -65
- data/lib/composite_primary_keys/relation/finder_methods.rb +196 -196
- data/lib/composite_primary_keys/sanitization.rb +52 -52
- data/lib/composite_primary_keys/validations/uniqueness.rb +37 -39
- data/lib/composite_primary_keys/version.rb +8 -8
- data/tasks/databases/sqlserver.rake +40 -27
- data/test/connections/databases.example.yml +18 -18
- data/test/connections/native_sqlserver/connection.rb +14 -11
- data/test/fixtures/db_definitions/mysql.sql +208 -208
- data/test/fixtures/db_definitions/postgresql.sql +210 -210
- data/test/fixtures/db_definitions/sqlite.sql +197 -197
- data/test/fixtures/db_definitions/sqlserver.drop.sql +94 -91
- data/test/fixtures/db_definitions/sqlserver.sql +232 -226
- data/test/fixtures/employee.rb +5 -5
- data/test/test_associations.rb +275 -275
- data/test/test_attributes.rb +60 -60
- data/test/test_create.rb +112 -112
- data/test/test_delete.rb +152 -148
- data/test/test_delete_all.rb +21 -21
- data/test/test_enum.rb +20 -20
- data/test/test_equal.rb +1 -1
- data/test/test_tutorial_example.rb +21 -21
- metadata +3 -2
@@ -1,46 +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 = build_scope.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
|
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 = build_scope.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
|
@@ -1,26 +1,26 @@
|
|
1
|
-
module ActiveRecord
|
2
|
-
module AttributeMethods
|
3
|
-
module Dirty
|
4
|
-
def write_attribute(attr, value)
|
5
|
-
# CPK
|
6
|
-
if attr.kind_of?(Array)
|
7
|
-
# A *composite* attribute can't be marked as changed! So do nothing now.
|
8
|
-
# We will come back in here with an *individual* attribute when Write#write_attribute looks through the individual attributes comprising this composite key:
|
9
|
-
# [attr_name, value].transpose.map {|name,val| write_attribute(name, val)}
|
10
|
-
else
|
11
|
-
attr = attr.to_s
|
12
|
-
|
13
|
-
save_changed_attribute(attr, value)
|
14
|
-
end
|
15
|
-
|
16
|
-
# Carry on.
|
17
|
-
super(attr, value)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
ActiveRecord::Base.class_eval do
|
24
|
-
alias :[]= :write_attribute
|
25
|
-
public :[]=
|
26
|
-
end
|
1
|
+
module ActiveRecord
|
2
|
+
module AttributeMethods
|
3
|
+
module Dirty
|
4
|
+
def write_attribute(attr, value)
|
5
|
+
# CPK
|
6
|
+
if attr.kind_of?(Array)
|
7
|
+
# A *composite* attribute can't be marked as changed! So do nothing now.
|
8
|
+
# We will come back in here with an *individual* attribute when Write#write_attribute looks through the individual attributes comprising this composite key:
|
9
|
+
# [attr_name, value].transpose.map {|name,val| write_attribute(name, val)}
|
10
|
+
else
|
11
|
+
attr = attr.to_s
|
12
|
+
|
13
|
+
save_changed_attribute(attr, value)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Carry on.
|
17
|
+
super(attr, value)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
ActiveRecord::Base.class_eval do
|
24
|
+
alias :[]= :write_attribute
|
25
|
+
public :[]=
|
26
|
+
end
|
@@ -1,35 +1,35 @@
|
|
1
|
-
module ActiveRecord
|
2
|
-
module AttributeMethods
|
3
|
-
module Read
|
4
|
-
def read_attribute(attr_name)
|
5
|
-
if attr_name.kind_of?(Array)
|
6
|
-
attr_name.map {|name| read_attribute(name)}.to_composite_keys
|
7
|
-
else
|
8
|
-
# If it's cached, just return it
|
9
|
-
# We use #[] first as a perf optimization for non-nil values. See https://gist.github.com/jonleighton/3552829.
|
10
|
-
name = attr_name.to_s
|
11
|
-
@attributes_cache[name] || @attributes_cache.fetch(name) {
|
12
|
-
column = @column_types_override[name] if @column_types_override
|
13
|
-
column ||= @column_types[name]
|
14
|
-
|
15
|
-
return @attributes.fetch(name) {
|
16
|
-
if name == 'id' && self.class.primary_key != name
|
17
|
-
read_attribute(self.class.primary_key)
|
18
|
-
end
|
19
|
-
} unless column
|
20
|
-
|
21
|
-
value = @attributes.fetch(name) {
|
22
|
-
return block_given? ? yield(name) : nil
|
23
|
-
}
|
24
|
-
|
25
|
-
if self.class.cache_attribute?(name)
|
26
|
-
@attributes_cache[name] = column.type_cast(value)
|
27
|
-
else
|
28
|
-
column.type_cast value
|
29
|
-
end
|
30
|
-
}
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
1
|
+
module ActiveRecord
|
2
|
+
module AttributeMethods
|
3
|
+
module Read
|
4
|
+
def read_attribute(attr_name)
|
5
|
+
if attr_name.kind_of?(Array)
|
6
|
+
attr_name.map {|name| read_attribute(name)}.to_composite_keys
|
7
|
+
else
|
8
|
+
# If it's cached, just return it
|
9
|
+
# We use #[] first as a perf optimization for non-nil values. See https://gist.github.com/jonleighton/3552829.
|
10
|
+
name = attr_name.to_s
|
11
|
+
@attributes_cache[name] || @attributes_cache.fetch(name) {
|
12
|
+
column = @column_types_override[name] if @column_types_override
|
13
|
+
column ||= @column_types[name]
|
14
|
+
|
15
|
+
return @attributes.fetch(name) {
|
16
|
+
if name == 'id' && self.class.primary_key != name
|
17
|
+
read_attribute(self.class.primary_key)
|
18
|
+
end
|
19
|
+
} unless column
|
20
|
+
|
21
|
+
value = @attributes.fetch(name) {
|
22
|
+
return block_given? ? yield(name) : nil
|
23
|
+
}
|
24
|
+
|
25
|
+
if self.class.cache_attribute?(name)
|
26
|
+
@attributes_cache[name] = column.type_cast(value)
|
27
|
+
else
|
28
|
+
column.type_cast value
|
29
|
+
end
|
30
|
+
}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
35
|
end
|
@@ -1,36 +1,36 @@
|
|
1
|
-
module ActiveRecord
|
2
|
-
module AttributeMethods
|
3
|
-
module Write
|
4
|
-
def write_attribute_with_type_cast(attr_name, value, type_cast_method)
|
5
|
-
# CPK
|
6
|
-
if attr_name.kind_of?(Array)
|
7
|
-
value = [nil]*attr_name.length if value.nil?
|
8
|
-
unless value.length == attr_name.length
|
9
|
-
raise "Number of attr_names #{attr_name.inspect} and values #{value.inspect} do not match"
|
10
|
-
end
|
11
|
-
[attr_name, value].transpose.map {|name,val| write_attribute(name, val)}
|
12
|
-
value
|
13
|
-
else
|
14
|
-
attr_name = attr_name.to_s
|
15
|
-
# CPK
|
16
|
-
# attr_name = self.class.primary_key if attr_name == 'id' && self.class.primary_key
|
17
|
-
attr_name = self.class.primary_key if attr_name == 'id' && self.class.primary_key && !self.composite?
|
18
|
-
@attributes_cache.delete(attr_name)
|
19
|
-
column = column_for_attribute(attr_name)
|
20
|
-
|
21
|
-
# If we're dealing with a binary column, write the data to the cache
|
22
|
-
# so we don't attempt to typecast multiple times.
|
23
|
-
if column && column.binary?
|
24
|
-
@attributes_cache[attr_name] = value
|
25
|
-
end
|
26
|
-
|
27
|
-
if column || @attributes.has_key?(attr_name)
|
28
|
-
@attributes[attr_name] = send(type_cast_method, column, value)
|
29
|
-
else
|
30
|
-
raise ActiveModel::MissingAttributeError, "can't write unknown attribute `#{attr_name}'"
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
1
|
+
module ActiveRecord
|
2
|
+
module AttributeMethods
|
3
|
+
module Write
|
4
|
+
def write_attribute_with_type_cast(attr_name, value, type_cast_method)
|
5
|
+
# CPK
|
6
|
+
if attr_name.kind_of?(Array)
|
7
|
+
value = [nil]*attr_name.length if value.nil?
|
8
|
+
unless value.length == attr_name.length
|
9
|
+
raise "Number of attr_names #{attr_name.inspect} and values #{value.inspect} do not match"
|
10
|
+
end
|
11
|
+
[attr_name, value].transpose.map {|name,val| write_attribute(name, val)}
|
12
|
+
value
|
13
|
+
else
|
14
|
+
attr_name = attr_name.to_s
|
15
|
+
# CPK
|
16
|
+
# attr_name = self.class.primary_key if attr_name == 'id' && self.class.primary_key
|
17
|
+
attr_name = self.class.primary_key if attr_name == 'id' && self.class.primary_key && !self.composite?
|
18
|
+
@attributes_cache.delete(attr_name)
|
19
|
+
column = column_for_attribute(attr_name)
|
20
|
+
|
21
|
+
# If we're dealing with a binary column, write the data to the cache
|
22
|
+
# so we don't attempt to typecast multiple times.
|
23
|
+
if column && column.binary?
|
24
|
+
@attributes_cache[attr_name] = value
|
25
|
+
end
|
26
|
+
|
27
|
+
if column || @attributes.has_key?(attr_name)
|
28
|
+
@attributes[attr_name] = send(type_cast_method, column, value)
|
29
|
+
else
|
30
|
+
raise ActiveModel::MissingAttributeError, "can't write unknown attribute `#{attr_name}'"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -111,12 +111,6 @@ module ActiveRecord
|
|
111
111
|
id
|
112
112
|
end
|
113
113
|
|
114
|
-
def ==(comparison_object)
|
115
|
-
return false if !persisted? && comparison_object.object_id != object_id
|
116
|
-
return true if equal? comparison_object
|
117
|
-
ids.is_a?(Array) ? super(comparison_object) && ids.all? {|id| !id.nil?} : super(comparison_object)
|
118
|
-
end
|
119
|
-
|
120
114
|
def can_change_primary_key_values?
|
121
115
|
false
|
122
116
|
end
|
@@ -1,30 +1,30 @@
|
|
1
|
-
module CompositePrimaryKeys
|
2
|
-
ID_SEP = ','
|
3
|
-
ID_SET_SEP = ';'
|
4
|
-
|
5
|
-
module ArrayExtension
|
6
|
-
def to_composite_keys
|
7
|
-
CompositeKeys.new(self)
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
class CompositeKeys < Array
|
12
|
-
def self.parse(value)
|
13
|
-
case value
|
14
|
-
when Array
|
15
|
-
value.to_composite_keys
|
16
|
-
when String
|
17
|
-
self.new(value.split(ID_SEP))
|
18
|
-
else
|
19
|
-
raise(ArgumentError, "Unsupported type: #{value}")
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def to_s
|
24
|
-
# Doing this makes it easier to parse Base#[](attr_name)
|
25
|
-
join(ID_SEP)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
Array.send(:include, CompositePrimaryKeys::ArrayExtension)
|
1
|
+
module CompositePrimaryKeys
|
2
|
+
ID_SEP = ','
|
3
|
+
ID_SET_SEP = ';'
|
4
|
+
|
5
|
+
module ArrayExtension
|
6
|
+
def to_composite_keys
|
7
|
+
CompositeKeys.new(self)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class CompositeKeys < Array
|
12
|
+
def self.parse(value)
|
13
|
+
case value
|
14
|
+
when Array
|
15
|
+
value.to_composite_keys
|
16
|
+
when String
|
17
|
+
self.new(value.split(ID_SEP))
|
18
|
+
else
|
19
|
+
raise(ArgumentError, "Unsupported type: #{value}")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_s
|
24
|
+
# Doing this makes it easier to parse Base#[](attr_name)
|
25
|
+
join(ID_SEP)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
Array.send(:include, CompositePrimaryKeys::ArrayExtension)
|
data/lib/composite_primary_keys/connection_adapters/abstract/connection_specification_changes.rb
CHANGED
@@ -4,6 +4,9 @@ module ActiveRecord
|
|
4
4
|
if (adapter.to_s =~ /postgresql/) or (adapter.to_s =~ /postgis/)
|
5
5
|
require "composite_primary_keys/connection_adapters/postgresql_adapter.rb"
|
6
6
|
end
|
7
|
+
if (adapter.to_s =~ /sqlserver/)
|
8
|
+
require "composite_primary_keys/connection_adapters/sqlserver_adapter.rb"
|
9
|
+
end
|
7
10
|
end
|
8
11
|
|
9
12
|
def self.establish_connection(spec = ENV["DATABASE_URL"])
|
@@ -61,8 +64,7 @@ module ActiveRecord
|
|
61
64
|
connection_handler.clear_active_connections!
|
62
65
|
end
|
63
66
|
|
64
|
-
delegate :clear_reloadable_connections!,
|
65
|
-
:clear_all_connections!,:verify_active_connections!, :to => :connection_handler
|
67
|
+
delegate :clear_reloadable_connections!, :clear_all_connections!, :to => :connection_handler
|
66
68
|
end
|
67
69
|
end
|
68
70
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
class SQLServerAdapter
|
4
|
+
def sql_for_insert(sql, pk, id_value, sequence_name, binds)
|
5
|
+
sql =
|
6
|
+
if pk
|
7
|
+
# support composite primary keys consisting of more than one column name
|
8
|
+
inserted_pks = [pk].flatten.map {|pk| "inserted.#{pk}"}
|
9
|
+
sql.insert(sql.index(/ (DEFAULT )?VALUES/), " OUTPUT #{inserted_pks.join(", ")}")
|
10
|
+
else
|
11
|
+
"#{sql}; SELECT CAST(SCOPE_IDENTITY() AS bigint) AS Ident"
|
12
|
+
end
|
13
|
+
[sql, binds]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -1,47 +1,47 @@
|
|
1
|
-
module ActiveRecord
|
2
|
-
module Core
|
3
|
-
def init_internals
|
4
|
-
pk = self.class.primary_key
|
5
|
-
|
6
|
-
# CPK
|
7
|
-
#@attributes[pk] = nil unless @attributes.key?(pk)
|
8
|
-
unless self.composite?
|
9
|
-
@attributes[pk] = nil unless @attributes.key?(pk)
|
10
|
-
end
|
11
|
-
|
12
|
-
@aggregation_cache = {}
|
13
|
-
@association_cache = {}
|
14
|
-
@attributes_cache = {}
|
15
|
-
@readonly = false
|
16
|
-
@destroyed = false
|
17
|
-
@marked_for_destruction = false
|
18
|
-
@destroyed_by_association = nil
|
19
|
-
@new_record = true
|
20
|
-
@txn = nil
|
21
|
-
@_start_transaction_state = {}
|
22
|
-
@transaction_state = nil
|
23
|
-
@reflects_state = [false]
|
24
|
-
end
|
25
|
-
|
26
|
-
def initialize_dup(other) # :nodoc:
|
27
|
-
cloned_attributes = other.clone_attributes(:read_attribute_before_type_cast)
|
28
|
-
self.class.initialize_attributes(cloned_attributes, :serialized => false)
|
29
|
-
|
30
|
-
@attributes = cloned_attributes
|
31
|
-
|
32
|
-
# CPK
|
33
|
-
#@attributes[self.class.primary_key] = nil
|
34
|
-
Array(self.class.primary_key).each {|key| @attributes[key] = nil}
|
35
|
-
|
36
|
-
run_callbacks(:initialize) unless _initialize_callbacks.empty?
|
37
|
-
|
38
|
-
@aggregation_cache = {}
|
39
|
-
@association_cache = {}
|
40
|
-
@attributes_cache = {}
|
41
|
-
|
42
|
-
@new_record = true
|
43
|
-
|
44
|
-
super
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
1
|
+
module ActiveRecord
|
2
|
+
module Core
|
3
|
+
def init_internals
|
4
|
+
pk = self.class.primary_key
|
5
|
+
|
6
|
+
# CPK
|
7
|
+
#@attributes[pk] = nil unless @attributes.key?(pk)
|
8
|
+
unless self.composite?
|
9
|
+
@attributes[pk] = nil unless @attributes.key?(pk)
|
10
|
+
end
|
11
|
+
|
12
|
+
@aggregation_cache = {}
|
13
|
+
@association_cache = {}
|
14
|
+
@attributes_cache = {}
|
15
|
+
@readonly = false
|
16
|
+
@destroyed = false
|
17
|
+
@marked_for_destruction = false
|
18
|
+
@destroyed_by_association = nil
|
19
|
+
@new_record = true
|
20
|
+
@txn = nil
|
21
|
+
@_start_transaction_state = {}
|
22
|
+
@transaction_state = nil
|
23
|
+
@reflects_state = [false]
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize_dup(other) # :nodoc:
|
27
|
+
cloned_attributes = other.clone_attributes(:read_attribute_before_type_cast)
|
28
|
+
self.class.initialize_attributes(cloned_attributes, :serialized => false)
|
29
|
+
|
30
|
+
@attributes = cloned_attributes
|
31
|
+
|
32
|
+
# CPK
|
33
|
+
#@attributes[self.class.primary_key] = nil
|
34
|
+
Array(self.class.primary_key).each {|key| @attributes[key] = nil}
|
35
|
+
|
36
|
+
run_callbacks(:initialize) unless _initialize_callbacks.empty?
|
37
|
+
|
38
|
+
@aggregation_cache = {}
|
39
|
+
@association_cache = {}
|
40
|
+
@attributes_cache = {}
|
41
|
+
|
42
|
+
@new_record = true
|
43
|
+
|
44
|
+
super
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|