composite_primary_keys 3.0.9 → 3.1.0
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 -0
- data/Rakefile +10 -1
- data/lib/composite_primary_keys.rb +75 -75
- data/lib/composite_primary_keys/base.rb +190 -194
- data/lib/composite_primary_keys/composite_arrays.rb +23 -23
- data/lib/composite_primary_keys/finder_methods.rb +0 -11
- data/lib/composite_primary_keys/reflection.rb +38 -38
- data/lib/composite_primary_keys/version.rb +2 -2
- data/test/abstract_unit.rb +3 -2
- data/test/connections/connection_spec.rb +1 -2
- data/test/connections/databases.example.yml +14 -12
- data/test/connections/databases.yml +14 -14
- data/test/connections/native_ibm_db/connection.rb +0 -3
- data/test/connections/native_mysql/connection.rb +3 -9
- data/test/connections/native_oracle/connection.rb +4 -10
- data/test/connections/native_oracle_enhanced/connection.rb +4 -11
- data/test/connections/native_postgresql/connection.rb +1 -3
- data/test/connections/native_sqlite/connection.rb +2 -4
- data/test/debug.log +589 -589
- data/test/fixtures/article.rb +5 -5
- data/test/fixtures/articles.yml +5 -5
- data/test/fixtures/capitol.rb +3 -0
- data/test/fixtures/capitols.yml +16 -0
- data/test/fixtures/db_definitions/mysql.sql +5 -0
- data/test/fixtures/db_definitions/postgresql.sql +5 -0
- data/test/fixtures/product.rb +7 -7
- data/test/fixtures/product_tariff.rb +5 -5
- data/test/fixtures/product_tariffs.yml +12 -12
- data/test/fixtures/products.yml +5 -5
- data/test/fixtures/reading.rb +4 -4
- data/test/fixtures/readings.yml +9 -9
- data/test/fixtures/reference_code.rb +7 -7
- data/test/fixtures/reference_codes.yml +29 -29
- data/test/fixtures/reference_type.rb +7 -7
- data/test/fixtures/reference_types.yml +9 -9
- data/test/fixtures/suburb.rb +5 -5
- data/test/fixtures/suburbs.yml +8 -8
- data/test/fixtures/tariff.rb +6 -6
- data/test/fixtures/tariffs.yml +12 -12
- data/test/fixtures/user.rb +10 -10
- data/test/fixtures/users.yml +5 -5
- data/test/hash_tricks.rb +34 -34
- data/test/test_associations.rb +180 -180
- data/test/test_attribute_methods.rb +0 -2
- data/test/test_attributes.rb +0 -5
- data/test/test_clone.rb +31 -33
- data/test/test_composite_arrays.rb +0 -2
- data/test/test_create.rb +0 -4
- data/test/test_delete.rb +92 -96
- data/test/test_equal.rb +21 -0
- data/test/test_exists.rb +0 -2
- data/test/test_find.rb +79 -76
- data/test/test_ids.rb +81 -83
- data/test/test_miscellaneous.rb +36 -38
- data/test/test_pagination.rb +35 -37
- data/test/test_polymorphic.rb +0 -6
- data/test/test_santiago.rb +23 -27
- data/test/test_suite.rb +1 -0
- data/test/test_tutorial_example.rb +0 -4
- data/test/test_update.rb +37 -39
- data/test/test_validations.rb +0 -1
- metadata +8 -4
data/History.txt
CHANGED
data/Rakefile
CHANGED
@@ -19,4 +19,13 @@ Rake::GemPackageTask.new(spec).define
|
|
19
19
|
# Now load in other task files
|
20
20
|
Dir.glob('tasks/**/*.rake').each do |rake_file|
|
21
21
|
load File.join(File.dirname(__FILE__), rake_file)
|
22
|
-
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Set up test tasks
|
25
|
+
for adapter in %w( mysql sqlite oracle oracle_enhanced postgresql ibm_db )
|
26
|
+
Rake::TestTask.new("test_#{adapter}") do |t|
|
27
|
+
t.libs << "test" << "test/connections/native_#{adapter}"
|
28
|
+
t.pattern = "test/test_*.rb"
|
29
|
+
t.verbose = true
|
30
|
+
end
|
31
|
+
end
|
@@ -1,75 +1,75 @@
|
|
1
|
-
#--
|
2
|
-
# Copyright (c) 2006 Nic Williams
|
3
|
-
#
|
4
|
-
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
-
# a copy of this software and associated documentation files (the
|
6
|
-
# "Software"), to deal in the Software without restriction, including
|
7
|
-
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
-
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
-
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
-
# the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be
|
13
|
-
# included in all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
-
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
-
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
-
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
-
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
-
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
-
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
-
#++
|
23
|
-
|
24
|
-
$:.unshift(File.dirname(__FILE__)) unless
|
25
|
-
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
26
|
-
|
27
|
-
unless defined?(ActiveRecord)
|
28
|
-
begin
|
29
|
-
require 'active_record'
|
30
|
-
rescue LoadError
|
31
|
-
require 'rubygems'
|
32
|
-
gem 'active_record'
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
require 'active_record/associations.rb'
|
37
|
-
require 'active_record/associations/association_proxy.rb'
|
38
|
-
require 'active_record/associations/association_collection'
|
39
|
-
require 'active_record/associations/association_proxy'
|
40
|
-
require 'active_record/associations/belongs_to_association'
|
41
|
-
require 'active_record/associations/belongs_to_polymorphic_association'
|
42
|
-
require 'active_record/associations/has_and_belongs_to_many_association'
|
43
|
-
require 'active_record/associations/has_many_association'
|
44
|
-
require 'active_record/associations/has_one_association'
|
45
|
-
require 'active_record/associations/has_one_through_association'
|
46
|
-
require 'active_record/associations/through_association_scope'
|
47
|
-
require 'active_record/relation/query_methods'
|
48
|
-
require 'active_record/attribute_methods/primary_key'
|
49
|
-
require 'active_record/fixtures'
|
50
|
-
|
51
|
-
require 'composite_primary_keys/composite_arrays'
|
52
|
-
require 'composite_primary_keys/associations'
|
53
|
-
require 'composite_primary_keys/associations/association_proxy'
|
54
|
-
require 'composite_primary_keys/associations/has_one_association'
|
55
|
-
require 'composite_primary_keys/associations/has_many_association'
|
56
|
-
require 'composite_primary_keys/associations/has_and_belongs_to_many_association'
|
57
|
-
require 'composite_primary_keys/associations/through_association_scope'
|
58
|
-
require 'composite_primary_keys/association_preload'
|
59
|
-
require 'composite_primary_keys/reflection'
|
60
|
-
require 'composite_primary_keys/relation'
|
61
|
-
require 'composite_primary_keys/read'
|
62
|
-
require 'composite_primary_keys/finder_methods'
|
63
|
-
require 'composite_primary_keys/base'
|
64
|
-
require 'composite_primary_keys/calculations'
|
65
|
-
require 'composite_primary_keys/validations/uniqueness'
|
66
|
-
require 'composite_primary_keys/query_methods'
|
67
|
-
require 'composite_primary_keys/primary_key'
|
68
|
-
require 'composite_primary_keys/fixtures'
|
69
|
-
|
70
|
-
Dir[File.dirname(__FILE__) + '/composite_primary_keys/connection_adapters/*.rb'].each do |adapter|
|
71
|
-
begin
|
72
|
-
require adapter.gsub('.rb','')
|
73
|
-
rescue MissingSourceFile
|
74
|
-
end
|
75
|
-
end
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2006 Nic Williams
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
#++
|
23
|
+
|
24
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
25
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
26
|
+
|
27
|
+
unless defined?(ActiveRecord)
|
28
|
+
begin
|
29
|
+
require 'active_record'
|
30
|
+
rescue LoadError
|
31
|
+
require 'rubygems'
|
32
|
+
gem 'active_record'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
require 'active_record/associations.rb'
|
37
|
+
require 'active_record/associations/association_proxy.rb'
|
38
|
+
require 'active_record/associations/association_collection'
|
39
|
+
require 'active_record/associations/association_proxy'
|
40
|
+
require 'active_record/associations/belongs_to_association'
|
41
|
+
require 'active_record/associations/belongs_to_polymorphic_association'
|
42
|
+
require 'active_record/associations/has_and_belongs_to_many_association'
|
43
|
+
require 'active_record/associations/has_many_association'
|
44
|
+
require 'active_record/associations/has_one_association'
|
45
|
+
require 'active_record/associations/has_one_through_association'
|
46
|
+
require 'active_record/associations/through_association_scope'
|
47
|
+
require 'active_record/relation/query_methods'
|
48
|
+
require 'active_record/attribute_methods/primary_key'
|
49
|
+
require 'active_record/fixtures'
|
50
|
+
|
51
|
+
require 'composite_primary_keys/composite_arrays'
|
52
|
+
require 'composite_primary_keys/associations'
|
53
|
+
require 'composite_primary_keys/associations/association_proxy'
|
54
|
+
require 'composite_primary_keys/associations/has_one_association'
|
55
|
+
require 'composite_primary_keys/associations/has_many_association'
|
56
|
+
require 'composite_primary_keys/associations/has_and_belongs_to_many_association'
|
57
|
+
require 'composite_primary_keys/associations/through_association_scope'
|
58
|
+
require 'composite_primary_keys/association_preload'
|
59
|
+
require 'composite_primary_keys/reflection'
|
60
|
+
require 'composite_primary_keys/relation'
|
61
|
+
require 'composite_primary_keys/read'
|
62
|
+
require 'composite_primary_keys/finder_methods'
|
63
|
+
require 'composite_primary_keys/base'
|
64
|
+
require 'composite_primary_keys/calculations'
|
65
|
+
require 'composite_primary_keys/validations/uniqueness'
|
66
|
+
require 'composite_primary_keys/query_methods'
|
67
|
+
require 'composite_primary_keys/primary_key'
|
68
|
+
require 'composite_primary_keys/fixtures'
|
69
|
+
|
70
|
+
Dir[File.dirname(__FILE__) + '/composite_primary_keys/connection_adapters/*.rb'].each do |adapter|
|
71
|
+
begin
|
72
|
+
require adapter.gsub('.rb','')
|
73
|
+
rescue MissingSourceFile
|
74
|
+
end
|
75
|
+
end
|
@@ -1,195 +1,191 @@
|
|
1
|
-
module ActiveRecord
|
2
|
-
class CompositeKeyError < StandardError #:nodoc:
|
3
|
-
end
|
4
|
-
|
5
|
-
class Base
|
6
|
-
INVALID_FOR_COMPOSITE_KEYS = 'Not appropriate for composite primary keys'
|
7
|
-
NOT_IMPLEMENTED_YET = 'Not implemented for composite primary keys yet'
|
8
|
-
|
9
|
-
class << self
|
10
|
-
def set_primary_keys(*keys)
|
11
|
-
keys = keys.first if keys.first.is_a?(Array)
|
12
|
-
|
13
|
-
if keys.length == 1
|
14
|
-
set_primary_key(keys.first)
|
15
|
-
return
|
16
|
-
end
|
17
|
-
|
18
|
-
cattr_accessor :primary_keys
|
19
|
-
self.primary_keys = keys.map { |k| k.to_sym }
|
20
|
-
|
21
|
-
class_eval <<-EOV
|
22
|
-
extend CompositeClassMethods
|
23
|
-
include CompositeInstanceMethods
|
24
|
-
include CompositePrimaryKeys::ActiveRecord::AssociationPreload
|
25
|
-
EOV
|
26
|
-
end
|
27
|
-
|
28
|
-
def composite?
|
29
|
-
false
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def composite?
|
34
|
-
self.class.composite?
|
35
|
-
end
|
36
|
-
|
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
|
-
module CompositeClassMethods
|
70
|
-
def primary_key
|
71
|
-
primary_keys
|
72
|
-
end
|
73
|
-
|
74
|
-
def primary_key=(keys)
|
75
|
-
primary_keys = keys
|
76
|
-
end
|
77
|
-
|
78
|
-
def composite?
|
79
|
-
true
|
80
|
-
end
|
81
|
-
|
82
|
-
#ids_to_s([[1,2],[7,3]]) -> "(1,2),(7,3)"
|
83
|
-
#ids_to_s([[1,2],[7,3]], ',', ';') -> "1,2;7,3"
|
84
|
-
def ids_to_s(many_ids, id_sep = CompositePrimaryKeys::ID_SEP, list_sep = ',', left_bracket = '(', right_bracket = ')')
|
85
|
-
many_ids.map {|ids| "#{left_bracket}#{CompositePrimaryKeys::CompositeKeys.new(ids)}#{right_bracket}"}.join(list_sep)
|
86
|
-
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
|
-
end
|
102
|
-
|
103
|
-
module CompositeInstanceMethods
|
104
|
-
# A model instance's primary keys is always available as model.ids
|
105
|
-
# whether you name it the default 'id' or set it to something else.
|
106
|
-
def id
|
107
|
-
attr_names = self.class.primary_keys
|
108
|
-
::CompositePrimaryKeys::CompositeKeys.new(attr_names.map { |attr_name| read_attribute(attr_name) })
|
109
|
-
end
|
110
|
-
alias_method :ids, :id
|
111
|
-
|
112
|
-
def ids_hash
|
113
|
-
self.class.primary_key.zip(ids).inject(Hash.new) do |hash, (key, value)|
|
114
|
-
hash[key] = value
|
115
|
-
hash
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
def
|
120
|
-
|
121
|
-
end
|
122
|
-
|
123
|
-
def
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
ids.
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
#
|
150
|
-
#
|
151
|
-
#
|
152
|
-
#
|
153
|
-
|
154
|
-
|
155
|
-
#
|
156
|
-
#
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
self.class.unscoped.where(ids_hash).arel.update(attributes_with_values)
|
192
|
-
end
|
193
|
-
end
|
194
|
-
end
|
1
|
+
module ActiveRecord
|
2
|
+
class CompositeKeyError < StandardError #:nodoc:
|
3
|
+
end
|
4
|
+
|
5
|
+
class Base
|
6
|
+
INVALID_FOR_COMPOSITE_KEYS = 'Not appropriate for composite primary keys'
|
7
|
+
NOT_IMPLEMENTED_YET = 'Not implemented for composite primary keys yet'
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def set_primary_keys(*keys)
|
11
|
+
keys = keys.first if keys.first.is_a?(Array)
|
12
|
+
|
13
|
+
if keys.length == 1
|
14
|
+
set_primary_key(keys.first)
|
15
|
+
return
|
16
|
+
end
|
17
|
+
|
18
|
+
cattr_accessor :primary_keys
|
19
|
+
self.primary_keys = keys.map { |k| k.to_sym }
|
20
|
+
|
21
|
+
class_eval <<-EOV
|
22
|
+
extend CompositeClassMethods
|
23
|
+
include CompositeInstanceMethods
|
24
|
+
include CompositePrimaryKeys::ActiveRecord::AssociationPreload
|
25
|
+
EOV
|
26
|
+
end
|
27
|
+
|
28
|
+
def composite?
|
29
|
+
false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def composite?
|
34
|
+
self.class.composite?
|
35
|
+
end
|
36
|
+
|
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
|
+
module CompositeClassMethods
|
70
|
+
def primary_key
|
71
|
+
primary_keys
|
72
|
+
end
|
73
|
+
|
74
|
+
def primary_key=(keys)
|
75
|
+
primary_keys = keys
|
76
|
+
end
|
77
|
+
|
78
|
+
def composite?
|
79
|
+
true
|
80
|
+
end
|
81
|
+
|
82
|
+
#ids_to_s([[1,2],[7,3]]) -> "(1,2),(7,3)"
|
83
|
+
#ids_to_s([[1,2],[7,3]], ',', ';') -> "1,2;7,3"
|
84
|
+
def ids_to_s(many_ids, id_sep = CompositePrimaryKeys::ID_SEP, list_sep = ',', left_bracket = '(', right_bracket = ')')
|
85
|
+
many_ids.map {|ids| "#{left_bracket}#{CompositePrimaryKeys::CompositeKeys.new(ids)}#{right_bracket}"}.join(list_sep)
|
86
|
+
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
|
+
end
|
102
|
+
|
103
|
+
module CompositeInstanceMethods
|
104
|
+
# A model instance's primary keys is always available as model.ids
|
105
|
+
# whether you name it the default 'id' or set it to something else.
|
106
|
+
def id
|
107
|
+
attr_names = self.class.primary_keys
|
108
|
+
::CompositePrimaryKeys::CompositeKeys.new(attr_names.map { |attr_name| read_attribute(attr_name) })
|
109
|
+
end
|
110
|
+
alias_method :ids, :id
|
111
|
+
|
112
|
+
def ids_hash
|
113
|
+
self.class.primary_key.zip(ids).inject(Hash.new) do |hash, (key, value)|
|
114
|
+
hash[key] = value
|
115
|
+
hash
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def id_before_type_cast #:nodoc:
|
120
|
+
raise CompositeKeyError, CompositePrimaryKeys::ActiveRecord::Base::NOT_IMPLEMENTED_YET
|
121
|
+
end
|
122
|
+
|
123
|
+
def quoted_id #:nodoc:
|
124
|
+
[self.class.primary_keys, ids].
|
125
|
+
transpose.
|
126
|
+
map {|attr_name,id| quote_value(id, column_for_attribute(attr_name))}.
|
127
|
+
to_composite_ids
|
128
|
+
end
|
129
|
+
|
130
|
+
# Sets the primary ID.
|
131
|
+
def id=(ids)
|
132
|
+
ids = ids.split(CompositePrimaryKeys::ID_SEP) if ids.is_a?(String)
|
133
|
+
ids.flatten!
|
134
|
+
unless ids.is_a?(Array) and ids.length == self.class.primary_keys.length
|
135
|
+
raise "#{self.class}.id= requires #{self.class.primary_keys.length} ids"
|
136
|
+
end
|
137
|
+
[primary_keys, ids].transpose.each {|key, an_id| write_attribute(key , an_id)}
|
138
|
+
id
|
139
|
+
end
|
140
|
+
|
141
|
+
# Cloned objects have no id assigned and are treated as new records. Note that this is a "shallow" clone
|
142
|
+
# as it copies the object's attributes only, not its associations. The extent of a "deep" clone is
|
143
|
+
# application specific and is therefore left to the application to implement according to its need.
|
144
|
+
def initialize_copy(other)
|
145
|
+
# Think the assertion which fails if the after_initialize callback goes at the end of the method is wrong. The
|
146
|
+
# deleted clone method called new which therefore called the after_initialize callback. It then went on to copy
|
147
|
+
# over the attributes. But if it's copying the attributes afterwards then it hasn't finished initializing right?
|
148
|
+
# For example in the test suite the topic model's after_initialize method sets the author_email_address to
|
149
|
+
# test@test.com. I would have thought this would mean that all cloned models would have an author email address
|
150
|
+
# of test@test.com. However the test_clone test method seems to test that this is not the case. As a result the
|
151
|
+
# after_initialize callback has to be run *before* the copying of the atrributes rather than afterwards in order
|
152
|
+
# for all tests to pass. This makes no sense to me.
|
153
|
+
callback(:after_initialize) if respond_to_without_attributes?(:after_initialize)
|
154
|
+
cloned_attributes = other.clone_attributes(:read_attribute_before_type_cast)
|
155
|
+
# CPK
|
156
|
+
#cloned_attributes.delete(self.class.primary_key)
|
157
|
+
self.class.primary_key.each {|key| cloned_attributes.delete(key.to_s)}
|
158
|
+
|
159
|
+
@attributes = cloned_attributes
|
160
|
+
clear_aggregation_cache
|
161
|
+
@attributes_cache = {}
|
162
|
+
@new_record = true
|
163
|
+
ensure_proper_type
|
164
|
+
|
165
|
+
if scope = self.class.send(:current_scoped_methods)
|
166
|
+
create_with = scope.scope_for_create
|
167
|
+
create_with.each { |att,value| self.send("#{att}=", value) } if create_with
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def destroy
|
172
|
+
if persisted?
|
173
|
+
# CPK
|
174
|
+
# self.class.unscoped.where(self.class.arel_table[self.class.primary_key].eq(id)).delete_all
|
175
|
+
self.class.unscoped.where(ids_hash).delete_all
|
176
|
+
end
|
177
|
+
|
178
|
+
@destroyed = true
|
179
|
+
freeze
|
180
|
+
end
|
181
|
+
|
182
|
+
def update(attribute_names = @attributes.keys)
|
183
|
+
attributes_with_values = arel_attributes_values(false, false, attribute_names)
|
184
|
+
return 0 if attributes_with_values.empty?
|
185
|
+
# CPK
|
186
|
+
# self.class.unscoped.where(self.class.arel_table[self.class.primary_key].eq(id)).arel.update(attributes_with_values)
|
187
|
+
self.class.unscoped.where(ids_hash).arel.update(attributes_with_values)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
195
191
|
end
|