ibm_db 1.1.1-mswin32
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/CHANGES +155 -0
- data/LICENSE +18 -0
- data/MANIFEST +14 -0
- data/README +274 -0
- data/ext/Makefile.nt32 +181 -0
- data/ext/extconf.rb +58 -0
- data/ext/ibm_db.c +6553 -0
- data/ext/ruby_ibm_db.h +214 -0
- data/init.rb +42 -0
- data/lib/IBM_DB.rb +2 -0
- data/lib/active_record/connection_adapters/ibm_db_adapter.rb +2218 -0
- data/lib/active_record/vendor/db2-i5-zOS.yaml +328 -0
- data/lib/mswin32/ibm_db.so +0 -0
- data/test/cases/adapter_test.rb +180 -0
- data/test/cases/associations/cascaded_eager_loading_test.rb +133 -0
- data/test/cases/associations/eager_test.rb +842 -0
- data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +874 -0
- data/test/cases/associations/has_many_through_associations_test.rb +281 -0
- data/test/cases/associations/join_model_test.rb +801 -0
- data/test/cases/attribute_methods_test.rb +312 -0
- data/test/cases/base_test.rb +2114 -0
- data/test/cases/calculations_test.rb +346 -0
- data/test/cases/finder_test.rb +1092 -0
- data/test/cases/fixtures_test.rb +660 -0
- data/test/cases/migration_test.rb +1618 -0
- data/test/cases/schema_dumper_test.rb +197 -0
- data/test/cases/validations_test.rb +1604 -0
- data/test/connections/native_ibm_db/connection.rb +40 -0
- data/test/ibm_db_test.rb +25 -0
- data/test/models/warehouse_thing.rb +5 -0
- data/test/schema/i5/ibm_db_specific_schema.rb +134 -0
- data/test/schema/ids/ibm_db_specific_schema.rb +137 -0
- data/test/schema/luw/ibm_db_specific_schema.rb +134 -0
- data/test/schema/schema.rb +499 -0
- data/test/schema/zOS/ibm_db_specific_schema.rb +205 -0
- metadata +115 -0
@@ -0,0 +1,281 @@
|
|
1
|
+
require "cases/helper"
|
2
|
+
require 'models/post'
|
3
|
+
require 'models/person'
|
4
|
+
require 'models/reference'
|
5
|
+
require 'models/job'
|
6
|
+
require 'models/reader'
|
7
|
+
require 'models/comment'
|
8
|
+
require 'models/tag'
|
9
|
+
require 'models/tagging'
|
10
|
+
require 'models/author'
|
11
|
+
require 'models/owner'
|
12
|
+
require 'models/pet'
|
13
|
+
require 'models/toy'
|
14
|
+
|
15
|
+
class HasManyThroughAssociationsTest < ActiveRecord::TestCase
|
16
|
+
fixtures :posts, :readers, :people, :comments, :authors, :owners, :pets, :toys
|
17
|
+
|
18
|
+
def test_associate_existing
|
19
|
+
assert_queries(2) { posts(:thinking);people(:david) }
|
20
|
+
|
21
|
+
posts(:thinking).people
|
22
|
+
|
23
|
+
assert_queries(1) do
|
24
|
+
posts(:thinking).people << people(:david)
|
25
|
+
end
|
26
|
+
|
27
|
+
assert_queries(1) do
|
28
|
+
assert posts(:thinking).people.include?(people(:david))
|
29
|
+
end
|
30
|
+
|
31
|
+
assert posts(:thinking).reload.people(true).include?(people(:david))
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_associating_new
|
35
|
+
assert_queries(1) { posts(:thinking) }
|
36
|
+
new_person = nil # so block binding catches it
|
37
|
+
|
38
|
+
assert_queries(0) do
|
39
|
+
new_person = Person.new :first_name => 'bob'
|
40
|
+
end
|
41
|
+
|
42
|
+
# Associating new records always saves them
|
43
|
+
# Thus, 1 query for the new person record, 1 query for the new join table record
|
44
|
+
assert_queries(2) do
|
45
|
+
posts(:thinking).people << new_person
|
46
|
+
end
|
47
|
+
|
48
|
+
assert_queries(1) do
|
49
|
+
assert posts(:thinking).people.include?(new_person)
|
50
|
+
end
|
51
|
+
|
52
|
+
assert posts(:thinking).reload.people(true).include?(new_person)
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_associate_new_by_building
|
56
|
+
assert_queries(1) { posts(:thinking) }
|
57
|
+
|
58
|
+
assert_queries(0) do
|
59
|
+
posts(:thinking).people.build(:first_name=>"Bob")
|
60
|
+
posts(:thinking).people.new(:first_name=>"Ted")
|
61
|
+
end
|
62
|
+
|
63
|
+
# Should only need to load the association once
|
64
|
+
assert_queries(1) do
|
65
|
+
assert posts(:thinking).people.collect(&:first_name).include?("Bob")
|
66
|
+
assert posts(:thinking).people.collect(&:first_name).include?("Ted")
|
67
|
+
end
|
68
|
+
|
69
|
+
# 2 queries for each new record (1 to save the record itself, 1 for the join model)
|
70
|
+
# * 2 new records = 4
|
71
|
+
# + 1 query to save the actual post = 5
|
72
|
+
assert_queries(5) do
|
73
|
+
posts(:thinking).body += '-changed'
|
74
|
+
posts(:thinking).save
|
75
|
+
end
|
76
|
+
|
77
|
+
assert posts(:thinking).reload.people(true).collect(&:first_name).include?("Bob")
|
78
|
+
assert posts(:thinking).reload.people(true).collect(&:first_name).include?("Ted")
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_delete_association
|
82
|
+
assert_queries(2){posts(:welcome);people(:michael); }
|
83
|
+
|
84
|
+
assert_queries(1) do
|
85
|
+
posts(:welcome).people.delete(people(:michael))
|
86
|
+
end
|
87
|
+
|
88
|
+
assert_queries(1) do
|
89
|
+
assert posts(:welcome).people.empty?
|
90
|
+
end
|
91
|
+
|
92
|
+
assert posts(:welcome).reload.people(true).empty?
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_destroy_association
|
96
|
+
assert_difference "Person.count", -1 do
|
97
|
+
posts(:welcome).people.destroy(people(:michael))
|
98
|
+
end
|
99
|
+
|
100
|
+
assert posts(:welcome).reload.people.empty?
|
101
|
+
assert posts(:welcome).people(true).empty?
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_destroy_all
|
105
|
+
assert_difference "Person.count", -1 do
|
106
|
+
posts(:welcome).people.destroy_all
|
107
|
+
end
|
108
|
+
|
109
|
+
assert posts(:welcome).reload.people.empty?
|
110
|
+
assert posts(:welcome).people(true).empty?
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_replace_association
|
114
|
+
assert_queries(4){posts(:welcome);people(:david);people(:michael); posts(:welcome).people(true)}
|
115
|
+
|
116
|
+
# 1 query to delete the existing reader (michael)
|
117
|
+
# 1 query to associate the new reader (david)
|
118
|
+
assert_queries(2) do
|
119
|
+
posts(:welcome).people = [people(:david)]
|
120
|
+
end
|
121
|
+
|
122
|
+
assert_queries(0){
|
123
|
+
assert posts(:welcome).people.include?(people(:david))
|
124
|
+
assert !posts(:welcome).people.include?(people(:michael))
|
125
|
+
}
|
126
|
+
|
127
|
+
assert posts(:welcome).reload.people(true).include?(people(:david))
|
128
|
+
assert !posts(:welcome).reload.people(true).include?(people(:michael))
|
129
|
+
end
|
130
|
+
|
131
|
+
def test_associate_with_create
|
132
|
+
assert_queries(1) { posts(:thinking) }
|
133
|
+
|
134
|
+
# 1 query for the new record, 1 for the join table record
|
135
|
+
# No need to update the actual collection yet!
|
136
|
+
assert_queries(2) do
|
137
|
+
posts(:thinking).people.create(:first_name=>"Jeb")
|
138
|
+
end
|
139
|
+
|
140
|
+
# *Now* we actually need the collection so it's loaded
|
141
|
+
assert_queries(1) do
|
142
|
+
assert posts(:thinking).people.collect(&:first_name).include?("Jeb")
|
143
|
+
end
|
144
|
+
|
145
|
+
assert posts(:thinking).reload.people(true).collect(&:first_name).include?("Jeb")
|
146
|
+
end
|
147
|
+
|
148
|
+
def test_associate_with_create_and_no_options
|
149
|
+
peeps = posts(:thinking).people.count
|
150
|
+
posts(:thinking).people.create(:first_name => 'foo')
|
151
|
+
assert_equal peeps + 1, posts(:thinking).people.count
|
152
|
+
end
|
153
|
+
|
154
|
+
def test_associate_with_create_exclamation_and_no_options
|
155
|
+
peeps = posts(:thinking).people.count
|
156
|
+
posts(:thinking).people.create!(:first_name => 'foo')
|
157
|
+
assert_equal peeps + 1, posts(:thinking).people.count
|
158
|
+
end
|
159
|
+
|
160
|
+
def test_clear_associations
|
161
|
+
assert_queries(2) { posts(:welcome);posts(:welcome).people(true) }
|
162
|
+
|
163
|
+
assert_queries(1) do
|
164
|
+
posts(:welcome).people.clear
|
165
|
+
end
|
166
|
+
|
167
|
+
assert_queries(0) do
|
168
|
+
assert posts(:welcome).people.empty?
|
169
|
+
end
|
170
|
+
|
171
|
+
assert posts(:welcome).reload.people(true).empty?
|
172
|
+
end
|
173
|
+
|
174
|
+
def test_association_callback_ordering
|
175
|
+
Post.reset_log
|
176
|
+
log = Post.log
|
177
|
+
post = posts(:thinking)
|
178
|
+
|
179
|
+
post.people_with_callbacks << people(:michael)
|
180
|
+
assert_equal [
|
181
|
+
[:added, :before, "Michael"],
|
182
|
+
[:added, :after, "Michael"]
|
183
|
+
], log.last(2)
|
184
|
+
|
185
|
+
post.people_with_callbacks.push(people(:david), Person.create!(:first_name => "Bob"), Person.new(:first_name => "Lary"))
|
186
|
+
assert_equal [
|
187
|
+
[:added, :before, "David"],
|
188
|
+
[:added, :after, "David"],
|
189
|
+
[:added, :before, "Bob"],
|
190
|
+
[:added, :after, "Bob"],
|
191
|
+
[:added, :before, "Lary"],
|
192
|
+
[:added, :after, "Lary"]
|
193
|
+
],log.last(6)
|
194
|
+
|
195
|
+
post.people_with_callbacks.build(:first_name => "Ted")
|
196
|
+
assert_equal [
|
197
|
+
[:added, :before, "Ted"],
|
198
|
+
[:added, :after, "Ted"]
|
199
|
+
], log.last(2)
|
200
|
+
|
201
|
+
post.people_with_callbacks.create(:first_name => "Sam")
|
202
|
+
assert_equal [
|
203
|
+
[:added, :before, "Sam"],
|
204
|
+
[:added, :after, "Sam"]
|
205
|
+
], log.last(2)
|
206
|
+
|
207
|
+
post.people_with_callbacks = [people(:michael),people(:david), Person.new(:first_name => "Julian"), Person.create!(:first_name => "Roger")]
|
208
|
+
assert_equal (%w(Ted Bob Sam Lary) * 2).sort, log[-12..-5].collect(&:last).sort
|
209
|
+
assert_equal [
|
210
|
+
[:added, :before, "Julian"],
|
211
|
+
[:added, :after, "Julian"],
|
212
|
+
[:added, :before, "Roger"],
|
213
|
+
[:added, :after, "Roger"]
|
214
|
+
], log.last(4)
|
215
|
+
|
216
|
+
post.people_with_callbacks.clear
|
217
|
+
assert_equal (%w(Michael David Julian Roger) * 2).sort, log.last(8).collect(&:last).sort
|
218
|
+
end
|
219
|
+
|
220
|
+
unless current_adapter?(:IBM_DBAdapter) #refer db2 ? SQL0214N
|
221
|
+
def test_dynamic_find_should_respect_association_include
|
222
|
+
# SQL error in sort clause if :include is not included
|
223
|
+
# due to Unknown column 'comments.id'
|
224
|
+
assert Person.find(1).posts_with_comments_sorted_by_comment_id.find_by_title('Welcome to the weblog')
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
def test_count_with_include_should_alias_join_table
|
229
|
+
assert_equal 2, people(:michael).posts.count(:include => :readers)
|
230
|
+
end
|
231
|
+
|
232
|
+
def test_inner_join_with_quoted_table_name
|
233
|
+
assert_equal 2, people(:michael).jobs.size
|
234
|
+
end
|
235
|
+
|
236
|
+
def test_get_ids
|
237
|
+
assert_equal [posts(:welcome).id, posts(:authorless).id].sort, people(:michael).post_ids.sort
|
238
|
+
end
|
239
|
+
|
240
|
+
def test_get_ids_for_loaded_associations
|
241
|
+
person = people(:michael)
|
242
|
+
person.posts(true)
|
243
|
+
assert_queries(0) do
|
244
|
+
person.post_ids
|
245
|
+
person.post_ids
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
def test_get_ids_for_unloaded_associations_does_not_load_them
|
250
|
+
person = people(:michael)
|
251
|
+
assert !person.posts.loaded?
|
252
|
+
assert_equal [posts(:welcome).id, posts(:authorless).id].sort, person.post_ids.sort
|
253
|
+
assert !person.posts.loaded?
|
254
|
+
end
|
255
|
+
|
256
|
+
def test_association_proxy_transaction_method_starts_transaction_in_association_class
|
257
|
+
Tag.expects(:transaction)
|
258
|
+
Post.find(:first).tags.transaction do
|
259
|
+
# nothing
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
def test_has_many_association_through_a_belongs_to_association_where_the_association_doesnt_exist
|
264
|
+
author = authors(:mary)
|
265
|
+
post = Post.create!(:title => "TITLE", :body => "BODY")
|
266
|
+
assert_equal [], post.author_favorites
|
267
|
+
end
|
268
|
+
|
269
|
+
def test_has_many_association_through_a_belongs_to_association
|
270
|
+
author = authors(:mary)
|
271
|
+
post = Post.create!(:author => author, :title => "TITLE", :body => "BODY")
|
272
|
+
author.author_favorites.create(:favorite_author_id => 1)
|
273
|
+
author.author_favorites.create(:favorite_author_id => 2)
|
274
|
+
author.author_favorites.create(:favorite_author_id => 3)
|
275
|
+
assert_equal post.author.author_favorites, post.author_favorites
|
276
|
+
end
|
277
|
+
|
278
|
+
def test_has_many_association_through_a_has_many_association_with_nonstandard_primary_keys
|
279
|
+
assert_equal 1, owners(:blackbeard).toys.count
|
280
|
+
end
|
281
|
+
end
|
@@ -0,0 +1,801 @@
|
|
1
|
+
require "cases/helper"
|
2
|
+
require 'models/tag'
|
3
|
+
require 'models/tagging'
|
4
|
+
require 'models/post'
|
5
|
+
require 'models/item'
|
6
|
+
require 'models/comment'
|
7
|
+
require 'models/author'
|
8
|
+
require 'models/category'
|
9
|
+
require 'models/categorization'
|
10
|
+
require 'models/vertex'
|
11
|
+
require 'models/edge'
|
12
|
+
require 'models/book'
|
13
|
+
require 'models/citation'
|
14
|
+
|
15
|
+
class AssociationsJoinModelTest < ActiveRecord::TestCase
|
16
|
+
self.use_transactional_fixtures = false
|
17
|
+
fixtures :posts, :authors, :categories, :categorizations, :comments, :tags, :taggings, :author_favorites, :vertices, :items, :books
|
18
|
+
|
19
|
+
def test_has_many
|
20
|
+
assert authors(:david).categories.include?(categories(:general))
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_has_many_inherited
|
24
|
+
assert authors(:mary).categories.include?(categories(:sti_test))
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_inherited_has_many
|
28
|
+
assert categories(:sti_test).authors.include?(authors(:mary))
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_has_many_uniq_through_join_model
|
32
|
+
assert_equal 2, authors(:mary).categorized_posts.size
|
33
|
+
assert_equal 1, authors(:mary).unique_categorized_posts.size
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_has_many_uniq_through_count
|
37
|
+
author = authors(:mary)
|
38
|
+
assert !authors(:mary).unique_categorized_posts.loaded?
|
39
|
+
assert_queries(1) { assert_equal 1, author.unique_categorized_posts.count }
|
40
|
+
assert_queries(1) { assert_equal 1, author.unique_categorized_posts.count(:title) }
|
41
|
+
assert_queries(1) { assert_equal 0, author.unique_categorized_posts.count(:title, :conditions => "title is NULL") }
|
42
|
+
assert !authors(:mary).unique_categorized_posts.loaded?
|
43
|
+
end
|
44
|
+
|
45
|
+
unless current_adapter?(:IBM_DBAdapter)
|
46
|
+
def test_has_many_uniq_through_find
|
47
|
+
assert_equal 1, authors(:mary).unique_categorized_posts.find(:all).size
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_has_many_uniq_through_dynamic_find
|
51
|
+
assert_equal 1, authors(:mary).unique_categorized_posts.find_all_by_title("So I was thinking").size
|
52
|
+
end
|
53
|
+
# LUW: [IBM][CLI Driver][DB2/LINUX] SQL0214N
|
54
|
+
# An expression in the ORDER BY clause in the following position,
|
55
|
+
# or starting with "DEVELOPERS" in the "ORDER BY" clause is not valid.
|
56
|
+
# Reason code = "2". SQLSTATE=42822 SQLCODE=-214:
|
57
|
+
# SELECT DISTINCT projects.id FROM projects
|
58
|
+
# LEFT OUTER JOIN developers_projects ON developers_projects.project_id = projects.id
|
59
|
+
# LEFT OUTER JOIN developers ON developers.id = developers_projects.developer_id
|
60
|
+
# ORDER BY developers.created_at
|
61
|
+
#
|
62
|
+
# i5: [IBM][CLI Driver][AS] SQL0214N
|
63
|
+
# An expression in the ORDER BY clause in the following position,
|
64
|
+
# or starting with "1" in the "CREATED_AT" clause is not valid.
|
65
|
+
# Reason code = "2". SQLSTATE=42822 SQLCODE=-214:
|
66
|
+
# SELECT DISTINCT projects.id FROM projects
|
67
|
+
# LEFT OUTER JOIN developers_projects ON developers_projects.project_id = projects.id
|
68
|
+
# LEFT OUTER JOIN developers ON developers.id = developers_projects.developer_id
|
69
|
+
# ORDER BY developers.created_at
|
70
|
+
#
|
71
|
+
# zOS 9:[IBM][CLI Driver][DB2] SQL0214N
|
72
|
+
# An expression in the ORDER BY clause in the following position,
|
73
|
+
# or starting with "CREATED_AT" in the "ORDER BY" clause is not valid.
|
74
|
+
# Reason code = "2". SQLSTATE=42822 SQLCODE=-214:
|
75
|
+
# SELECT DISTINCT projects.id FROM projects
|
76
|
+
# LEFT OUTER JOIN developers_projects ON developers_projects.project_id = projects.id
|
77
|
+
# LEFT OUTER JOIN developers ON developers.id = developers_projects.developer_id
|
78
|
+
# ORDER BY developers.created_at
|
79
|
+
#
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_polymorphic_has_many
|
83
|
+
assert posts(:welcome).taggings.include?(taggings(:welcome_general))
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_polymorphic_has_one
|
87
|
+
assert_equal taggings(:welcome_general), posts(:welcome).tagging
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_polymorphic_belongs_to
|
91
|
+
assert_equal posts(:welcome), posts(:welcome).taggings.first.taggable
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_polymorphic_has_many_going_through_join_model
|
95
|
+
assert_equal tags(:general), tag = posts(:welcome).tags.first
|
96
|
+
assert_no_queries do
|
97
|
+
tag.tagging
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_count_polymorphic_has_many
|
102
|
+
assert_equal 1, posts(:welcome).taggings.count
|
103
|
+
assert_equal 1, posts(:welcome).tags.count
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_polymorphic_has_many_going_through_join_model_with_find
|
107
|
+
assert_equal tags(:general), tag = posts(:welcome).tags.find(:first)
|
108
|
+
assert_no_queries do
|
109
|
+
tag.tagging
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_polymorphic_has_many_going_through_join_model_with_include_on_source_reflection
|
114
|
+
assert_equal tags(:general), tag = posts(:welcome).funky_tags.first
|
115
|
+
assert_no_queries do
|
116
|
+
tag.tagging
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def test_polymorphic_has_many_going_through_join_model_with_include_on_source_reflection_with_find
|
121
|
+
assert_equal tags(:general), tag = posts(:welcome).funky_tags.find(:first)
|
122
|
+
assert_no_queries do
|
123
|
+
tag.tagging
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_polymorphic_has_many_going_through_join_model_with_disabled_include
|
128
|
+
assert_equal tags(:general), tag = posts(:welcome).tags.add_joins_and_select.first
|
129
|
+
assert_queries 1 do
|
130
|
+
tag.tagging
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_polymorphic_has_many_going_through_join_model_with_custom_select_and_joins
|
135
|
+
assert_equal tags(:general), tag = posts(:welcome).tags.add_joins_and_select.first
|
136
|
+
tag.author_id
|
137
|
+
end
|
138
|
+
|
139
|
+
def test_polymorphic_has_many_going_through_join_model_with_custom_foreign_key
|
140
|
+
assert_equal tags(:misc), taggings(:welcome_general).super_tag
|
141
|
+
assert_equal tags(:misc), posts(:welcome).super_tags.first
|
142
|
+
end
|
143
|
+
|
144
|
+
def test_polymorphic_has_many_create_model_with_inheritance_and_custom_base_class
|
145
|
+
post = SubStiPost.create :title => 'SubStiPost', :body => 'SubStiPost body'
|
146
|
+
assert_instance_of SubStiPost, post
|
147
|
+
|
148
|
+
tagging = tags(:misc).taggings.create(:taggable => post)
|
149
|
+
assert_equal "SubStiPost", tagging.taggable_type
|
150
|
+
end
|
151
|
+
|
152
|
+
def test_polymorphic_has_many_going_through_join_model_with_inheritance
|
153
|
+
assert_equal tags(:general), posts(:thinking).tags.first
|
154
|
+
end
|
155
|
+
|
156
|
+
def test_polymorphic_has_many_going_through_join_model_with_inheritance_with_custom_class_name
|
157
|
+
assert_equal tags(:general), posts(:thinking).funky_tags.first
|
158
|
+
end
|
159
|
+
|
160
|
+
def test_polymorphic_has_many_create_model_with_inheritance
|
161
|
+
post = posts(:thinking)
|
162
|
+
assert_instance_of SpecialPost, post
|
163
|
+
|
164
|
+
tagging = tags(:misc).taggings.create(:taggable => post)
|
165
|
+
assert_equal "Post", tagging.taggable_type
|
166
|
+
end
|
167
|
+
|
168
|
+
def test_polymorphic_has_one_create_model_with_inheritance
|
169
|
+
tagging = tags(:misc).create_tagging(:taggable => posts(:thinking))
|
170
|
+
assert_equal "Post", tagging.taggable_type
|
171
|
+
end
|
172
|
+
|
173
|
+
def test_set_polymorphic_has_many
|
174
|
+
tagging = tags(:misc).taggings.create
|
175
|
+
posts(:thinking).taggings << tagging
|
176
|
+
assert_equal "Post", tagging.taggable_type
|
177
|
+
end
|
178
|
+
|
179
|
+
def test_set_polymorphic_has_one
|
180
|
+
tagging = tags(:misc).taggings.create
|
181
|
+
posts(:thinking).tagging = tagging
|
182
|
+
assert_equal "Post", tagging.taggable_type
|
183
|
+
end
|
184
|
+
|
185
|
+
def test_create_polymorphic_has_many_with_scope
|
186
|
+
old_count = posts(:welcome).taggings.count
|
187
|
+
tagging = posts(:welcome).taggings.create(:tag => tags(:misc))
|
188
|
+
assert_equal "Post", tagging.taggable_type
|
189
|
+
assert_equal old_count+1, posts(:welcome).taggings.count
|
190
|
+
end
|
191
|
+
|
192
|
+
def test_create_bang_polymorphic_with_has_many_scope
|
193
|
+
old_count = posts(:welcome).taggings.count
|
194
|
+
tagging = posts(:welcome).taggings.create!(:tag => tags(:misc))
|
195
|
+
assert_equal "Post", tagging.taggable_type
|
196
|
+
assert_equal old_count+1, posts(:welcome).taggings.count
|
197
|
+
end
|
198
|
+
|
199
|
+
def test_create_polymorphic_has_one_with_scope
|
200
|
+
old_count = Tagging.count
|
201
|
+
tagging = posts(:welcome).tagging.create(:tag => tags(:misc))
|
202
|
+
assert_equal "Post", tagging.taggable_type
|
203
|
+
assert_equal old_count+1, Tagging.count
|
204
|
+
end
|
205
|
+
|
206
|
+
def test_delete_polymorphic_has_many_with_delete_all
|
207
|
+
assert_equal 1, posts(:welcome).taggings.count
|
208
|
+
posts(:welcome).taggings.first.update_attribute :taggable_type, 'PostWithHasManyDeleteAll'
|
209
|
+
post = find_post_with_dependency(1, :has_many, :taggings, :delete_all)
|
210
|
+
|
211
|
+
old_count = Tagging.count
|
212
|
+
post.destroy
|
213
|
+
assert_equal old_count-1, Tagging.count
|
214
|
+
assert_equal 0, posts(:welcome).taggings.count
|
215
|
+
end
|
216
|
+
|
217
|
+
def test_delete_polymorphic_has_many_with_destroy
|
218
|
+
assert_equal 1, posts(:welcome).taggings.count
|
219
|
+
posts(:welcome).taggings.first.update_attribute :taggable_type, 'PostWithHasManyDestroy'
|
220
|
+
post = find_post_with_dependency(1, :has_many, :taggings, :destroy)
|
221
|
+
|
222
|
+
old_count = Tagging.count
|
223
|
+
post.destroy
|
224
|
+
assert_equal old_count-1, Tagging.count
|
225
|
+
assert_equal 0, posts(:welcome).taggings.count
|
226
|
+
end
|
227
|
+
|
228
|
+
def test_delete_polymorphic_has_many_with_nullify
|
229
|
+
assert_equal 1, posts(:welcome).taggings.count
|
230
|
+
posts(:welcome).taggings.first.update_attribute :taggable_type, 'PostWithHasManyNullify'
|
231
|
+
post = find_post_with_dependency(1, :has_many, :taggings, :nullify)
|
232
|
+
|
233
|
+
old_count = Tagging.count
|
234
|
+
post.destroy
|
235
|
+
assert_equal old_count, Tagging.count
|
236
|
+
assert_equal 0, posts(:welcome).taggings.count
|
237
|
+
end
|
238
|
+
|
239
|
+
def test_delete_polymorphic_has_one_with_destroy
|
240
|
+
assert posts(:welcome).tagging
|
241
|
+
posts(:welcome).tagging.update_attribute :taggable_type, 'PostWithHasOneDestroy'
|
242
|
+
post = find_post_with_dependency(1, :has_one, :tagging, :destroy)
|
243
|
+
|
244
|
+
old_count = Tagging.count
|
245
|
+
post.destroy
|
246
|
+
assert_equal old_count-1, Tagging.count
|
247
|
+
assert_nil posts(:welcome).tagging(true)
|
248
|
+
end
|
249
|
+
|
250
|
+
def test_delete_polymorphic_has_one_with_nullify
|
251
|
+
assert posts(:welcome).tagging
|
252
|
+
posts(:welcome).tagging.update_attribute :taggable_type, 'PostWithHasOneNullify'
|
253
|
+
post = find_post_with_dependency(1, :has_one, :tagging, :nullify)
|
254
|
+
|
255
|
+
old_count = Tagging.count
|
256
|
+
post.destroy
|
257
|
+
assert_equal old_count, Tagging.count
|
258
|
+
assert_nil posts(:welcome).tagging(true)
|
259
|
+
end
|
260
|
+
|
261
|
+
def test_has_many_with_piggyback
|
262
|
+
assert_equal "2", categories(:sti_test).authors.first.post_id.to_s
|
263
|
+
end
|
264
|
+
|
265
|
+
def test_include_has_many_through
|
266
|
+
posts = Post.find(:all, :order => 'posts.id')
|
267
|
+
posts_with_authors = Post.find(:all, :include => :authors, :order => 'posts.id')
|
268
|
+
assert_equal posts.length, posts_with_authors.length
|
269
|
+
posts.length.times do |i|
|
270
|
+
assert_equal posts[i].authors.length, assert_no_queries { posts_with_authors[i].authors.length }
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
def test_include_polymorphic_has_one
|
275
|
+
post = Post.find_by_id(posts(:welcome).id, :include => :tagging)
|
276
|
+
tagging = taggings(:welcome_general)
|
277
|
+
assert_no_queries do
|
278
|
+
assert_equal tagging, post.tagging
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
def test_include_polymorphic_has_one_defined_in_abstract_parent
|
283
|
+
item = Item.find_by_id(items(:dvd).id, :include => :tagging)
|
284
|
+
tagging = taggings(:godfather)
|
285
|
+
assert_no_queries do
|
286
|
+
assert_equal tagging, item.tagging
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
def test_include_polymorphic_has_many_through
|
291
|
+
posts = Post.find(:all, :order => 'posts.id')
|
292
|
+
posts_with_tags = Post.find(:all, :include => :tags, :order => 'posts.id')
|
293
|
+
assert_equal posts.length, posts_with_tags.length
|
294
|
+
posts.length.times do |i|
|
295
|
+
assert_equal posts[i].tags.length, assert_no_queries { posts_with_tags[i].tags.length }
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
def test_include_polymorphic_has_many
|
300
|
+
posts = Post.find(:all, :order => 'posts.id')
|
301
|
+
posts_with_taggings = Post.find(:all, :include => :taggings, :order => 'posts.id')
|
302
|
+
assert_equal posts.length, posts_with_taggings.length
|
303
|
+
posts.length.times do |i|
|
304
|
+
assert_equal posts[i].taggings.length, assert_no_queries { posts_with_taggings[i].taggings.length }
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
def test_has_many_find_all
|
309
|
+
assert_equal [categories(:general)], authors(:david).categories.find(:all)
|
310
|
+
end
|
311
|
+
|
312
|
+
def test_has_many_find_first
|
313
|
+
assert_equal categories(:general), authors(:david).categories.find(:first)
|
314
|
+
end
|
315
|
+
|
316
|
+
def test_has_many_with_hash_conditions
|
317
|
+
assert_equal categories(:general), authors(:david).categories_like_general.find(:first)
|
318
|
+
end
|
319
|
+
|
320
|
+
def test_has_many_find_conditions
|
321
|
+
assert_equal categories(:general), authors(:david).categories.find(:first, :conditions => "categories.name = 'General'")
|
322
|
+
assert_equal nil, authors(:david).categories.find(:first, :conditions => "categories.name = 'Technology'")
|
323
|
+
end
|
324
|
+
|
325
|
+
def test_has_many_class_methods_called_by_method_missing
|
326
|
+
assert_equal categories(:general), authors(:david).categories.find_all_by_name('General').first
|
327
|
+
assert_equal nil, authors(:david).categories.find_by_name('Technology')
|
328
|
+
end
|
329
|
+
|
330
|
+
def test_has_many_array_methods_called_by_method_missing
|
331
|
+
assert true, authors(:david).categories.any? { |category| category.name == 'General' }
|
332
|
+
assert_nothing_raised { authors(:david).categories.sort }
|
333
|
+
end
|
334
|
+
|
335
|
+
def test_has_many_going_through_join_model_with_custom_foreign_key
|
336
|
+
assert_equal [], posts(:thinking).authors
|
337
|
+
assert_equal [authors(:mary)], posts(:authorless).authors
|
338
|
+
end
|
339
|
+
|
340
|
+
def test_both_scoped_and_explicit_joins_should_be_respected
|
341
|
+
assert_nothing_raised do
|
342
|
+
Post.send(:with_scope, :find => {:joins => "left outer join comments on comments.id = posts.id"}) do
|
343
|
+
Post.find :all, :select => "comments.id, authors.id", :joins => "left outer join authors on authors.id = posts.author_id"
|
344
|
+
end
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
def test_belongs_to_polymorphic_with_counter_cache
|
349
|
+
assert_equal 0, posts(:welcome)[:taggings_count]
|
350
|
+
tagging = posts(:welcome).taggings.create(:tag => tags(:general))
|
351
|
+
assert_equal 1, posts(:welcome, :reload)[:taggings_count]
|
352
|
+
tagging.destroy
|
353
|
+
assert posts(:welcome, :reload)[:taggings_count].zero?
|
354
|
+
end
|
355
|
+
|
356
|
+
def test_unavailable_through_reflection
|
357
|
+
assert_raise(ActiveRecord::HasManyThroughAssociationNotFoundError) { authors(:david).nothings }
|
358
|
+
end
|
359
|
+
|
360
|
+
def test_has_many_through_join_model_with_conditions
|
361
|
+
assert_equal [], posts(:welcome).invalid_taggings
|
362
|
+
assert_equal [], posts(:welcome).invalid_tags
|
363
|
+
end
|
364
|
+
|
365
|
+
def test_has_many_polymorphic
|
366
|
+
assert_raise ActiveRecord::HasManyThroughAssociationPolymorphicError do
|
367
|
+
assert_equal posts(:welcome, :thinking), tags(:general).taggables
|
368
|
+
end
|
369
|
+
assert_raise ActiveRecord::EagerLoadPolymorphicError do
|
370
|
+
assert_equal posts(:welcome, :thinking), tags(:general).taggings.find(:all, :include => :taggable, :conditions => 'bogus_table.column = 1')
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
def test_has_many_polymorphic_with_source_type
|
375
|
+
assert_equal posts(:welcome, :thinking), tags(:general).tagged_posts
|
376
|
+
end
|
377
|
+
|
378
|
+
def test_eager_has_many_polymorphic_with_source_type
|
379
|
+
tag_with_include = Tag.find(tags(:general).id, :include => :tagged_posts)
|
380
|
+
desired = posts(:welcome, :thinking)
|
381
|
+
assert_no_queries do
|
382
|
+
assert_equal desired, tag_with_include.tagged_posts
|
383
|
+
end
|
384
|
+
assert_equal 5, tag_with_include.taggings.length
|
385
|
+
end
|
386
|
+
|
387
|
+
def test_has_many_through_has_many_find_all
|
388
|
+
assert_equal comments(:greetings), authors(:david).comments.find(:all, :order => 'comments.id').first
|
389
|
+
end
|
390
|
+
|
391
|
+
def test_has_many_through_has_many_find_all_with_custom_class
|
392
|
+
assert_equal comments(:greetings), authors(:david).funky_comments.find(:all, :order => 'comments.id').first
|
393
|
+
end
|
394
|
+
|
395
|
+
def test_has_many_through_has_many_find_first
|
396
|
+
assert_equal comments(:greetings), authors(:david).comments.find(:first, :order => 'comments.id')
|
397
|
+
end
|
398
|
+
|
399
|
+
def test_has_many_through_has_many_find_conditions
|
400
|
+
options = { :conditions => "comments.#{QUOTED_TYPE}='SpecialComment'", :order => 'comments.id' }
|
401
|
+
assert_equal comments(:does_it_hurt), authors(:david).comments.find(:first, options)
|
402
|
+
end
|
403
|
+
|
404
|
+
def test_has_many_through_has_many_find_by_id
|
405
|
+
assert_equal comments(:more_greetings), authors(:david).comments.find(2)
|
406
|
+
end
|
407
|
+
|
408
|
+
def test_has_many_through_polymorphic_has_one
|
409
|
+
assert_raise(ActiveRecord::HasManyThroughSourceAssociationMacroError) { authors(:david).tagging }
|
410
|
+
end
|
411
|
+
|
412
|
+
def test_has_many_through_polymorphic_has_many
|
413
|
+
assert_equal taggings(:welcome_general, :thinking_general), authors(:david).taggings.uniq.sort_by { |t| t.id }
|
414
|
+
end
|
415
|
+
|
416
|
+
def test_include_has_many_through_polymorphic_has_many
|
417
|
+
author = Author.find_by_id(authors(:david).id, :include => :taggings)
|
418
|
+
expected_taggings = taggings(:welcome_general, :thinking_general)
|
419
|
+
assert_no_queries do
|
420
|
+
assert_equal expected_taggings, author.taggings.uniq.sort_by { |t| t.id }
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
def test_has_many_through_has_many_through
|
425
|
+
assert_raise(ActiveRecord::HasManyThroughSourceAssociationMacroError) { authors(:david).tags }
|
426
|
+
end
|
427
|
+
|
428
|
+
def test_has_many_through_habtm
|
429
|
+
assert_raise(ActiveRecord::HasManyThroughSourceAssociationMacroError) { authors(:david).post_categories }
|
430
|
+
end
|
431
|
+
|
432
|
+
unless current_adapter?(:IBM_DBAdapter)
|
433
|
+
def test_eager_load_has_many_through_has_many
|
434
|
+
author = Author.find :first, :conditions => ['name = ?', 'David'], :include => :comments, :order => 'comments.id'
|
435
|
+
SpecialComment.new; VerySpecialComment.new
|
436
|
+
assert_no_queries do
|
437
|
+
assert_equal [1,2,3,5,6,7,8,9,10], author.comments.collect(&:id)
|
438
|
+
end
|
439
|
+
end
|
440
|
+
# LUW: [IBM][CLI Driver][DB2/LINUX] SQL0214N
|
441
|
+
# An expression in the ORDER BY clause in the following position,
|
442
|
+
# or starting with "DEVELOPERS" in the "ORDER BY" clause is not valid.
|
443
|
+
# Reason code = "2". SQLSTATE=42822 SQLCODE=-214:
|
444
|
+
# SELECT DISTINCT projects.id FROM projects
|
445
|
+
# LEFT OUTER JOIN developers_projects ON developers_projects.project_id = projects.id
|
446
|
+
# LEFT OUTER JOIN developers ON developers.id = developers_projects.developer_id
|
447
|
+
# ORDER BY developers.created_at
|
448
|
+
#
|
449
|
+
# i5: [IBM][CLI Driver][AS] SQL0214N
|
450
|
+
# An expression in the ORDER BY clause in the following position,
|
451
|
+
# or starting with "1" in the "CREATED_AT" clause is not valid.
|
452
|
+
# Reason code = "2". SQLSTATE=42822 SQLCODE=-214:
|
453
|
+
# SELECT DISTINCT projects.id FROM projects
|
454
|
+
# LEFT OUTER JOIN developers_projects ON developers_projects.project_id = projects.id
|
455
|
+
# LEFT OUTER JOIN developers ON developers.id = developers_projects.developer_id
|
456
|
+
# ORDER BY developers.created_at
|
457
|
+
#
|
458
|
+
# zOS 9:[IBM][CLI Driver][DB2] SQL0214N
|
459
|
+
# An expression in the ORDER BY clause in the following position,
|
460
|
+
# or starting with "CREATED_AT" in the "ORDER BY" clause is not valid.
|
461
|
+
# Reason code = "2". SQLSTATE=42822 SQLCODE=-214:
|
462
|
+
# SELECT DISTINCT projects.id FROM projects
|
463
|
+
# LEFT OUTER JOIN developers_projects ON developers_projects.project_id = projects.id
|
464
|
+
# LEFT OUTER JOIN developers ON developers.id = developers_projects.developer_id
|
465
|
+
# ORDER BY developers.created_at
|
466
|
+
#
|
467
|
+
end
|
468
|
+
|
469
|
+
def test_eager_load_has_many_through_has_many_with_conditions
|
470
|
+
post = Post.find(:first, :include => :invalid_tags)
|
471
|
+
assert_no_queries do
|
472
|
+
post.invalid_tags
|
473
|
+
end
|
474
|
+
end
|
475
|
+
|
476
|
+
def test_eager_belongs_to_and_has_one_not_singularized
|
477
|
+
assert_nothing_raised do
|
478
|
+
Author.find(:first, :include => :author_address)
|
479
|
+
AuthorAddress.find(:first, :include => :author)
|
480
|
+
end
|
481
|
+
end
|
482
|
+
|
483
|
+
def test_self_referential_has_many_through
|
484
|
+
assert_equal [authors(:mary)], authors(:david).favorite_authors
|
485
|
+
assert_equal [], authors(:mary).favorite_authors
|
486
|
+
end
|
487
|
+
|
488
|
+
def test_add_to_self_referential_has_many_through
|
489
|
+
new_author = Author.create(:name => "Bob")
|
490
|
+
authors(:david).author_favorites.create :favorite_author => new_author
|
491
|
+
assert_equal new_author, authors(:david).reload.favorite_authors.first
|
492
|
+
end
|
493
|
+
|
494
|
+
def test_has_many_through_uses_conditions_specified_on_the_has_many_association
|
495
|
+
author = Author.find(:first)
|
496
|
+
assert !author.comments.blank?
|
497
|
+
assert author.nonexistant_comments.blank?
|
498
|
+
end
|
499
|
+
|
500
|
+
def test_has_many_through_uses_correct_attributes
|
501
|
+
assert_nil posts(:thinking).tags.find_by_name("General").attributes["tag_id"]
|
502
|
+
end
|
503
|
+
|
504
|
+
def test_associating_unsaved_records_with_has_many_through
|
505
|
+
saved_post = posts(:thinking)
|
506
|
+
new_tag = Tag.new(:name => "new")
|
507
|
+
|
508
|
+
saved_post.tags << new_tag
|
509
|
+
assert !new_tag.new_record? #consistent with habtm!
|
510
|
+
assert !saved_post.new_record?
|
511
|
+
assert saved_post.tags.include?(new_tag)
|
512
|
+
|
513
|
+
assert !new_tag.new_record?
|
514
|
+
assert saved_post.reload.tags(true).include?(new_tag)
|
515
|
+
|
516
|
+
|
517
|
+
new_post = Post.new(:title => "Association replacmenet works!", :body => "You best believe it.")
|
518
|
+
saved_tag = tags(:general)
|
519
|
+
|
520
|
+
new_post.tags << saved_tag
|
521
|
+
assert new_post.new_record?
|
522
|
+
assert !saved_tag.new_record?
|
523
|
+
assert new_post.tags.include?(saved_tag)
|
524
|
+
|
525
|
+
new_post.save!
|
526
|
+
assert !new_post.new_record?
|
527
|
+
assert new_post.reload.tags(true).include?(saved_tag)
|
528
|
+
|
529
|
+
assert posts(:thinking).tags.build.new_record?
|
530
|
+
assert posts(:thinking).tags.new.new_record?
|
531
|
+
end
|
532
|
+
|
533
|
+
def test_create_associate_when_adding_to_has_many_through
|
534
|
+
count = posts(:thinking).tags.count
|
535
|
+
push = Tag.create!(:name => 'pushme')
|
536
|
+
post_thinking = posts(:thinking)
|
537
|
+
assert_nothing_raised { post_thinking.tags << push }
|
538
|
+
assert_nil( wrong = post_thinking.tags.detect { |t| t.class != Tag },
|
539
|
+
message = "Expected a Tag in tags collection, got #{wrong.class}.")
|
540
|
+
assert_nil( wrong = post_thinking.taggings.detect { |t| t.class != Tagging },
|
541
|
+
message = "Expected a Tagging in taggings collection, got #{wrong.class}.")
|
542
|
+
assert_equal(count + 1, post_thinking.tags.size)
|
543
|
+
assert_equal(count + 1, post_thinking.tags(true).size)
|
544
|
+
|
545
|
+
assert_kind_of Tag, post_thinking.tags.create!(:name => 'foo')
|
546
|
+
assert_nil( wrong = post_thinking.tags.detect { |t| t.class != Tag },
|
547
|
+
message = "Expected a Tag in tags collection, got #{wrong.class}.")
|
548
|
+
assert_nil( wrong = post_thinking.taggings.detect { |t| t.class != Tagging },
|
549
|
+
message = "Expected a Tagging in taggings collection, got #{wrong.class}.")
|
550
|
+
assert_equal(count + 2, post_thinking.tags.size)
|
551
|
+
assert_equal(count + 2, post_thinking.tags(true).size)
|
552
|
+
|
553
|
+
assert_nothing_raised { post_thinking.tags.concat(Tag.create!(:name => 'abc'), Tag.create!(:name => 'def')) }
|
554
|
+
assert_nil( wrong = post_thinking.tags.detect { |t| t.class != Tag },
|
555
|
+
message = "Expected a Tag in tags collection, got #{wrong.class}.")
|
556
|
+
assert_nil( wrong = post_thinking.taggings.detect { |t| t.class != Tagging },
|
557
|
+
message = "Expected a Tagging in taggings collection, got #{wrong.class}.")
|
558
|
+
assert_equal(count + 4, post_thinking.tags.size)
|
559
|
+
assert_equal(count + 4, post_thinking.tags(true).size)
|
560
|
+
|
561
|
+
# Raises if the wrong reflection name is used to set the Edge belongs_to
|
562
|
+
assert_nothing_raised { vertices(:vertex_1).sinks << vertices(:vertex_5) }
|
563
|
+
end
|
564
|
+
|
565
|
+
def test_has_many_through_collection_size_doesnt_load_target_if_not_loaded
|
566
|
+
author = authors(:david)
|
567
|
+
assert_equal 9, author.comments.size
|
568
|
+
assert !author.comments.loaded?
|
569
|
+
end
|
570
|
+
|
571
|
+
def test_has_many_through_collection_size_uses_counter_cache_if_it_exists
|
572
|
+
author = authors(:david)
|
573
|
+
author.stubs(:read_attribute).with('comments_count').returns(100)
|
574
|
+
assert_equal 100, author.comments.size
|
575
|
+
assert !author.comments.loaded?
|
576
|
+
end
|
577
|
+
|
578
|
+
def test_adding_junk_to_has_many_through_should_raise_type_mismatch
|
579
|
+
assert_raise(ActiveRecord::AssociationTypeMismatch) { posts(:thinking).tags << "Uhh what now?" }
|
580
|
+
end
|
581
|
+
|
582
|
+
def test_adding_to_has_many_through_should_return_self
|
583
|
+
tags = posts(:thinking).tags
|
584
|
+
assert_equal tags, posts(:thinking).tags.push(tags(:general))
|
585
|
+
end
|
586
|
+
|
587
|
+
def test_delete_associate_when_deleting_from_has_many_through_with_nonstandard_id
|
588
|
+
count = books(:awdr).references.count
|
589
|
+
references_before = books(:awdr).references
|
590
|
+
book = Book.create!(:name => 'Getting Real')
|
591
|
+
book_awdr = books(:awdr)
|
592
|
+
book_awdr.references << book
|
593
|
+
assert_equal(count + 1, book_awdr.references(true).size)
|
594
|
+
|
595
|
+
assert_nothing_raised { book_awdr.references.delete(book) }
|
596
|
+
assert_equal(count, book_awdr.references.size)
|
597
|
+
assert_equal(count, book_awdr.references(true).size)
|
598
|
+
assert_equal(references_before.sort, book_awdr.references.sort)
|
599
|
+
end
|
600
|
+
|
601
|
+
def test_delete_associate_when_deleting_from_has_many_through
|
602
|
+
count = posts(:thinking).tags.count
|
603
|
+
tags_before = posts(:thinking).tags
|
604
|
+
tag = Tag.create!(:name => 'doomed')
|
605
|
+
post_thinking = posts(:thinking)
|
606
|
+
post_thinking.tags << tag
|
607
|
+
assert_equal(count + 1, post_thinking.taggings(true).size)
|
608
|
+
assert_equal(count + 1, post_thinking.tags(true).size)
|
609
|
+
|
610
|
+
assert_nothing_raised { post_thinking.tags.delete(tag) }
|
611
|
+
assert_equal(count, post_thinking.tags.size)
|
612
|
+
assert_equal(count, post_thinking.tags(true).size)
|
613
|
+
assert_equal(count, post_thinking.taggings(true).size)
|
614
|
+
assert_equal(tags_before.sort, post_thinking.tags.sort)
|
615
|
+
end
|
616
|
+
|
617
|
+
def test_delete_associate_when_deleting_from_has_many_through_with_multiple_tags
|
618
|
+
count = posts(:thinking).tags.count
|
619
|
+
tags_before = posts(:thinking).tags
|
620
|
+
doomed = Tag.create!(:name => 'doomed')
|
621
|
+
doomed2 = Tag.create!(:name => 'doomed2')
|
622
|
+
quaked = Tag.create!(:name => 'quaked')
|
623
|
+
post_thinking = posts(:thinking)
|
624
|
+
post_thinking.tags << doomed << doomed2
|
625
|
+
assert_equal(count + 2, post_thinking.tags(true).size)
|
626
|
+
|
627
|
+
assert_nothing_raised { post_thinking.tags.delete(doomed, doomed2, quaked) }
|
628
|
+
assert_equal(count, post_thinking.tags.size)
|
629
|
+
assert_equal(count, post_thinking.tags(true).size)
|
630
|
+
assert_equal(tags_before.sort, post_thinking.tags.sort)
|
631
|
+
end
|
632
|
+
|
633
|
+
def test_deleting_junk_from_has_many_through_should_raise_type_mismatch
|
634
|
+
assert_raise(ActiveRecord::AssociationTypeMismatch) { posts(:thinking).tags.delete("Uhh what now?") }
|
635
|
+
end
|
636
|
+
|
637
|
+
def test_has_many_through_sum_uses_calculations
|
638
|
+
assert_nothing_raised { authors(:david).comments.sum(:post_id) }
|
639
|
+
end
|
640
|
+
|
641
|
+
def test_calculations_on_has_many_through_should_disambiguate_fields
|
642
|
+
assert_nothing_raised { authors(:david).categories.maximum(:id) }
|
643
|
+
end
|
644
|
+
|
645
|
+
def test_calculations_on_has_many_through_should_not_disambiguate_fields_unless_necessary
|
646
|
+
assert_nothing_raised { authors(:david).categories.maximum("categories.id") }
|
647
|
+
end
|
648
|
+
|
649
|
+
def test_has_many_through_has_many_with_sti
|
650
|
+
assert_equal [comments(:does_it_hurt)], authors(:david).special_post_comments
|
651
|
+
end
|
652
|
+
|
653
|
+
def test_uniq_has_many_through_should_retain_order
|
654
|
+
comment_ids = authors(:david).comments.map(&:id)
|
655
|
+
assert_equal comment_ids.sort, authors(:david).ordered_uniq_comments.map(&:id)
|
656
|
+
|
657
|
+
unless current_adapter?(:IBM_DBAdapter)
|
658
|
+
assert_equal comment_ids.sort.reverse, authors(:david).ordered_uniq_comments_desc.map(&:id)
|
659
|
+
# LUW: [IBM][CLI Driver][DB2/LINUX] SQL0214N
|
660
|
+
# An expression in the ORDER BY clause in the following position,
|
661
|
+
# or starting with "DEVELOPERS" in the "ORDER BY" clause is not valid.
|
662
|
+
# Reason code = "2". SQLSTATE=42822 SQLCODE=-214:
|
663
|
+
# SELECT DISTINCT projects.id FROM projects
|
664
|
+
# LEFT OUTER JOIN developers_projects ON developers_projects.project_id = projects.id
|
665
|
+
# LEFT OUTER JOIN developers ON developers.id = developers_projects.developer_id
|
666
|
+
# ORDER BY developers.created_at
|
667
|
+
#
|
668
|
+
# i5: [IBM][CLI Driver][AS] SQL0214N
|
669
|
+
# An expression in the ORDER BY clause in the following position,
|
670
|
+
# or starting with "1" in the "CREATED_AT" clause is not valid.
|
671
|
+
# Reason code = "2". SQLSTATE=42822 SQLCODE=-214:
|
672
|
+
# SELECT DISTINCT projects.id FROM projects
|
673
|
+
# LEFT OUTER JOIN developers_projects ON developers_projects.project_id = projects.id
|
674
|
+
# LEFT OUTER JOIN developers ON developers.id = developers_projects.developer_id
|
675
|
+
# ORDER BY developers.created_at
|
676
|
+
#
|
677
|
+
# zOS 9:[IBM][CLI Driver][DB2] SQL0214N
|
678
|
+
# An expression in the ORDER BY clause in the following position,
|
679
|
+
# or starting with "CREATED_AT" in the "ORDER BY" clause is not valid.
|
680
|
+
# Reason code = "2". SQLSTATE=42822 SQLCODE=-214:
|
681
|
+
# SELECT DISTINCT projects.id FROM projects
|
682
|
+
# LEFT OUTER JOIN developers_projects ON developers_projects.project_id = projects.id
|
683
|
+
# LEFT OUTER JOIN developers ON developers.id = developers_projects.developer_id
|
684
|
+
# ORDER BY developers.created_at
|
685
|
+
#
|
686
|
+
end
|
687
|
+
end
|
688
|
+
|
689
|
+
def test_polymorphic_has_many
|
690
|
+
expected = taggings(:welcome_general)
|
691
|
+
p = Post.find(posts(:welcome).id, :include => :taggings)
|
692
|
+
assert_no_queries {assert p.taggings.include?(expected)}
|
693
|
+
assert posts(:welcome).taggings.include?(taggings(:welcome_general))
|
694
|
+
end
|
695
|
+
|
696
|
+
def test_polymorphic_has_one
|
697
|
+
expected = posts(:welcome)
|
698
|
+
|
699
|
+
tagging = Tagging.find(taggings(:welcome_general).id, :include => :taggable)
|
700
|
+
assert_no_queries { assert_equal expected, tagging.taggable}
|
701
|
+
end
|
702
|
+
|
703
|
+
def test_polymorphic_belongs_to
|
704
|
+
p = Post.find(posts(:welcome).id, :include => {:taggings => :taggable})
|
705
|
+
assert_no_queries {assert_equal posts(:welcome), p.taggings.first.taggable}
|
706
|
+
end
|
707
|
+
|
708
|
+
def test_preload_polymorphic_has_many_through
|
709
|
+
posts = Post.find(:all, :order => 'posts.id')
|
710
|
+
posts_with_tags = Post.find(:all, :include => :tags, :order => 'posts.id')
|
711
|
+
assert_equal posts.length, posts_with_tags.length
|
712
|
+
posts.length.times do |i|
|
713
|
+
assert_equal posts[i].tags.length, assert_no_queries { posts_with_tags[i].tags.length }
|
714
|
+
end
|
715
|
+
end
|
716
|
+
|
717
|
+
def test_preload_polymorph_many_types
|
718
|
+
taggings = Tagging.find :all, :include => :taggable, :conditions => ['taggable_type != ?', 'FakeModel']
|
719
|
+
assert_no_queries do
|
720
|
+
taggings.first.taggable.id
|
721
|
+
taggings[1].taggable.id
|
722
|
+
end
|
723
|
+
|
724
|
+
taggables = taggings.map(&:taggable)
|
725
|
+
assert taggables.include?(items(:dvd))
|
726
|
+
assert taggables.include?(posts(:welcome))
|
727
|
+
end
|
728
|
+
|
729
|
+
def test_preload_nil_polymorphic_belongs_to
|
730
|
+
assert_nothing_raised do
|
731
|
+
taggings = Tagging.find(:all, :include => :taggable, :conditions => ['taggable_type IS NULL'])
|
732
|
+
end
|
733
|
+
end
|
734
|
+
|
735
|
+
def test_preload_polymorphic_has_many
|
736
|
+
posts = Post.find(:all, :order => 'posts.id')
|
737
|
+
posts_with_taggings = Post.find(:all, :include => :taggings, :order => 'posts.id')
|
738
|
+
assert_equal posts.length, posts_with_taggings.length
|
739
|
+
posts.length.times do |i|
|
740
|
+
assert_equal posts[i].taggings.length, assert_no_queries { posts_with_taggings[i].taggings.length }
|
741
|
+
end
|
742
|
+
end
|
743
|
+
|
744
|
+
def test_belongs_to_shared_parent
|
745
|
+
comments = Comment.find(:all, :include => :post, :conditions => 'post_id = 1')
|
746
|
+
assert_no_queries do
|
747
|
+
assert_equal comments.first.post, comments[1].post
|
748
|
+
end
|
749
|
+
end
|
750
|
+
|
751
|
+
def test_has_many_through_include_uses_array_include_after_loaded
|
752
|
+
david = authors(:david)
|
753
|
+
david.categories.class # force load target
|
754
|
+
|
755
|
+
category = david.categories.first
|
756
|
+
|
757
|
+
assert_no_queries do
|
758
|
+
assert david.categories.loaded?
|
759
|
+
assert david.categories.include?(category)
|
760
|
+
end
|
761
|
+
end
|
762
|
+
|
763
|
+
def test_has_many_through_include_checks_if_record_exists_if_target_not_loaded
|
764
|
+
david = authors(:david)
|
765
|
+
category = david.categories.first
|
766
|
+
|
767
|
+
david.reload
|
768
|
+
assert ! david.categories.loaded?
|
769
|
+
assert_queries(1) do
|
770
|
+
assert david.categories.include?(category)
|
771
|
+
end
|
772
|
+
assert ! david.categories.loaded?
|
773
|
+
end
|
774
|
+
|
775
|
+
unless current_adapter?(:IBM_DBAdapter) #works fine stand alone, however when run as part of whole suite it breaks unique constraint
|
776
|
+
def test_has_many_through_include_returns_false_for_non_matching_record_to_verify_scoping
|
777
|
+
david = authors(:david)
|
778
|
+
category = Category.create!(:name => 'Not Associated')
|
779
|
+
|
780
|
+
assert ! david.categories.loaded?
|
781
|
+
assert ! david.categories.include?(category)
|
782
|
+
end
|
783
|
+
end
|
784
|
+
def test_has_many_through_goes_through_all_sti_classes
|
785
|
+
sub_sti_post = SubStiPost.create!(:title => 'test', :body => 'test', :author_id => 1)
|
786
|
+
new_comment = sub_sti_post.comments.create(:body => 'test')
|
787
|
+
|
788
|
+
assert_equal [9, 10, new_comment.id], authors(:david).sti_post_comments.map(&:id).sort
|
789
|
+
end
|
790
|
+
|
791
|
+
private
|
792
|
+
# create dynamic Post models to allow different dependency options
|
793
|
+
def find_post_with_dependency(post_id, association, association_name, dependency)
|
794
|
+
class_name = "PostWith#{association.to_s.classify}#{dependency.to_s.classify}"
|
795
|
+
Post.find(post_id).update_attribute :type, class_name
|
796
|
+
klass = Object.const_set(class_name, Class.new(ActiveRecord::Base))
|
797
|
+
klass.set_table_name 'posts'
|
798
|
+
klass.send(association, association_name, :as => :taggable, :dependent => dependency)
|
799
|
+
klass.find(post_id)
|
800
|
+
end
|
801
|
+
end
|