ibm_db 2.5.6-x86-mingw32
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 +181 -0
- data/LICENSE +18 -0
- data/MANIFEST +14 -0
- data/ParameterizedQueries README +39 -0
- data/README +282 -0
- data/ext/Makefile.nt32 +181 -0
- data/ext/extconf.rb +66 -0
- data/ext/ibm_db.c +11166 -0
- data/ext/ruby_ibm_db.h +236 -0
- data/ext/ruby_ibm_db_cli.c +738 -0
- data/ext/ruby_ibm_db_cli.h +431 -0
- data/init.rb +42 -0
- data/lib/IBM_DB.rb +2 -0
- data/lib/active_record/connection_adapters/ibm_db_adapter.rb +2598 -0
- data/lib/active_record/connection_adapters/ibm_db_pstmt.rb +1965 -0
- data/lib/active_record/vendor/db2-i5-zOS.yaml +328 -0
- data/lib/mswin32/ibm_db.rb +1 -0
- data/lib/mswin32/rb18x/ibm_db.so +0 -0
- data/lib/mswin32/rb19x/ibm_db.so +0 -0
- data/test/cases/adapter_test.rb +202 -0
- data/test/cases/associations/belongs_to_associations_test.rb +486 -0
- data/test/cases/associations/cascaded_eager_loading_test.rb +183 -0
- data/test/cases/associations/eager_test.rb +862 -0
- data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +917 -0
- data/test/cases/associations/has_many_through_associations_test.rb +461 -0
- data/test/cases/associations/join_model_test.rb +793 -0
- data/test/cases/attribute_methods_test.rb +621 -0
- data/test/cases/base_test.rb +1486 -0
- data/test/cases/calculations_test.rb +362 -0
- data/test/cases/finder_test.rb +1088 -0
- data/test/cases/fixtures_test.rb +684 -0
- data/test/cases/migration_test.rb +2014 -0
- data/test/cases/schema_dumper_test.rb +232 -0
- data/test/cases/validations/uniqueness_validation_test.rb +283 -0
- data/test/connections/native_ibm_db/connection.rb +42 -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 +135 -0
- data/test/schema/ids/ibm_db_specific_schema.rb +138 -0
- data/test/schema/luw/ibm_db_specific_schema.rb +135 -0
- data/test/schema/schema.rb +647 -0
- data/test/schema/zOS/ibm_db_specific_schema.rb +206 -0
- metadata +123 -0
@@ -0,0 +1,917 @@
|
|
1
|
+
require "cases/helper"
|
2
|
+
require 'models/developer'
|
3
|
+
require 'models/project'
|
4
|
+
require 'models/company'
|
5
|
+
require 'models/customer'
|
6
|
+
require 'models/order'
|
7
|
+
require 'models/categorization'
|
8
|
+
require 'models/category'
|
9
|
+
require 'models/post'
|
10
|
+
require 'models/author'
|
11
|
+
require 'models/tag'
|
12
|
+
require 'models/tagging'
|
13
|
+
require 'models/parrot'
|
14
|
+
require 'models/pirate'
|
15
|
+
require 'models/treasure'
|
16
|
+
require 'models/price_estimate'
|
17
|
+
require 'models/club'
|
18
|
+
require 'models/member'
|
19
|
+
require 'models/membership'
|
20
|
+
require 'models/sponsor'
|
21
|
+
require 'models/country'
|
22
|
+
require 'models/treaty'
|
23
|
+
require 'active_support/core_ext/string/conversions'
|
24
|
+
|
25
|
+
class ProjectWithAfterCreateHook < ActiveRecord::Base
|
26
|
+
set_table_name 'projects'
|
27
|
+
has_and_belongs_to_many :developers,
|
28
|
+
:class_name => "DeveloperForProjectWithAfterCreateHook",
|
29
|
+
:join_table => "developers_projects",
|
30
|
+
:foreign_key => "project_id",
|
31
|
+
:association_foreign_key => "developer_id"
|
32
|
+
|
33
|
+
after_create :add_david
|
34
|
+
|
35
|
+
def add_david
|
36
|
+
david = DeveloperForProjectWithAfterCreateHook.find_by_name('David')
|
37
|
+
david.projects << self
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class DeveloperForProjectWithAfterCreateHook < ActiveRecord::Base
|
42
|
+
set_table_name 'developers'
|
43
|
+
has_and_belongs_to_many :projects,
|
44
|
+
:class_name => "ProjectWithAfterCreateHook",
|
45
|
+
:join_table => "developers_projects",
|
46
|
+
:association_foreign_key => "project_id",
|
47
|
+
:foreign_key => "developer_id"
|
48
|
+
end
|
49
|
+
|
50
|
+
class ProjectWithSymbolsForKeys < ActiveRecord::Base
|
51
|
+
set_table_name 'projects'
|
52
|
+
has_and_belongs_to_many :developers,
|
53
|
+
:class_name => "DeveloperWithSymbolsForKeys",
|
54
|
+
:join_table => :developers_projects,
|
55
|
+
:foreign_key => :project_id,
|
56
|
+
:association_foreign_key => "developer_id"
|
57
|
+
end
|
58
|
+
|
59
|
+
class DeveloperWithSymbolsForKeys < ActiveRecord::Base
|
60
|
+
set_table_name 'developers'
|
61
|
+
has_and_belongs_to_many :projects,
|
62
|
+
:class_name => "ProjectWithSymbolsForKeys",
|
63
|
+
:join_table => :developers_projects,
|
64
|
+
:association_foreign_key => :project_id,
|
65
|
+
:foreign_key => "developer_id"
|
66
|
+
end
|
67
|
+
|
68
|
+
class DeveloperWithCounterSQL < ActiveRecord::Base
|
69
|
+
set_table_name 'developers'
|
70
|
+
has_and_belongs_to_many :projects,
|
71
|
+
:class_name => "DeveloperWithCounterSQL",
|
72
|
+
:join_table => "developers_projects",
|
73
|
+
:association_foreign_key => "project_id",
|
74
|
+
:foreign_key => "developer_id",
|
75
|
+
:counter_sql => 'SELECT COUNT(*) AS count_all FROM projects INNER JOIN developers_projects ON projects.id = developers_projects.project_id WHERE developers_projects.developer_id =#{id}'
|
76
|
+
end
|
77
|
+
|
78
|
+
if current_adapter?(:IBM_DBAdapter)
|
79
|
+
class Novel < ActiveRecord::Base
|
80
|
+
has_and_belongs_to_many :writers
|
81
|
+
end
|
82
|
+
|
83
|
+
class Writer < ActiveRecord::Base
|
84
|
+
has_and_belongs_to_many :novels
|
85
|
+
end
|
86
|
+
|
87
|
+
class NovelsWriter < ActiveRecord::Base
|
88
|
+
belongs_to :writers
|
89
|
+
belongs_to :novels
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
|
94
|
+
fixtures :accounts, :companies, :categories, :posts, :categories_posts, :developers, :projects, :developers_projects,
|
95
|
+
:parrots, :pirates, :treasures, :price_estimates, :tags, :taggings
|
96
|
+
|
97
|
+
def setup_data_for_habtm_case
|
98
|
+
ActiveRecord::Base.connection.execute('delete from countries_treaties')
|
99
|
+
|
100
|
+
country = Country.new(:name => 'India')
|
101
|
+
country.country_id = 'c1'
|
102
|
+
country.save!
|
103
|
+
|
104
|
+
treaty = Treaty.new(:name => 'peace')
|
105
|
+
treaty.treaty_id = 't1'
|
106
|
+
country.treaties << treaty
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_should_property_quote_string_primary_keys
|
110
|
+
setup_data_for_habtm_case
|
111
|
+
|
112
|
+
con = ActiveRecord::Base.connection
|
113
|
+
sql = 'select * from countries_treaties'
|
114
|
+
record = con.select_rows(sql).last
|
115
|
+
assert_equal 'c1', record[0]
|
116
|
+
assert_equal 't1', record[1]
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_should_record_timestamp_for_join_table
|
120
|
+
setup_data_for_habtm_case
|
121
|
+
|
122
|
+
con = ActiveRecord::Base.connection
|
123
|
+
sql = 'select * from countries_treaties'
|
124
|
+
record = con.select_rows(sql).last
|
125
|
+
assert_not_nil record[2]
|
126
|
+
assert_not_nil record[3]
|
127
|
+
if current_adapter?(:Mysql2Adapter, :OracleAdapter)
|
128
|
+
assert_match %r{\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}}, record[2].to_s(:db)
|
129
|
+
assert_match %r{\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}}, record[3].to_s(:db)
|
130
|
+
else
|
131
|
+
assert_match %r{\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}}, record[2]
|
132
|
+
assert_match %r{\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}}, record[3]
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_should_record_timestamp_for_join_table_only_if_timestamp_should_be_recorded
|
137
|
+
begin
|
138
|
+
Treaty.record_timestamps = false
|
139
|
+
setup_data_for_habtm_case
|
140
|
+
|
141
|
+
con = ActiveRecord::Base.connection
|
142
|
+
sql = 'select * from countries_treaties'
|
143
|
+
record = con.select_rows(sql).last
|
144
|
+
assert_nil record[2]
|
145
|
+
assert_nil record[3]
|
146
|
+
ensure
|
147
|
+
Treaty.record_timestamps = true
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def test_has_and_belongs_to_many
|
152
|
+
david = Developer.find(1)
|
153
|
+
|
154
|
+
assert !david.projects.empty?
|
155
|
+
assert_equal 2, david.projects.size
|
156
|
+
|
157
|
+
active_record = Project.find(1)
|
158
|
+
assert !active_record.developers.empty?
|
159
|
+
assert_equal 3, active_record.developers.size
|
160
|
+
assert active_record.developers.include?(david)
|
161
|
+
end
|
162
|
+
|
163
|
+
def test_triple_equality
|
164
|
+
assert !(Array === Developer.find(1).projects)
|
165
|
+
assert Developer.find(1).projects === Array
|
166
|
+
end
|
167
|
+
|
168
|
+
def test_adding_single
|
169
|
+
jamis = Developer.find(2)
|
170
|
+
jamis.projects.reload # causing the collection to load
|
171
|
+
action_controller = Project.find(2)
|
172
|
+
assert_equal 1, jamis.projects.size
|
173
|
+
assert_equal 1, action_controller.developers.size
|
174
|
+
|
175
|
+
jamis.projects << action_controller
|
176
|
+
|
177
|
+
assert_equal 2, jamis.projects.size
|
178
|
+
assert_equal 2, jamis.projects(true).size
|
179
|
+
assert_equal 2, action_controller.developers(true).size
|
180
|
+
end
|
181
|
+
|
182
|
+
def test_adding_type_mismatch
|
183
|
+
jamis = Developer.find(2)
|
184
|
+
assert_raise(ActiveRecord::AssociationTypeMismatch) { jamis.projects << nil }
|
185
|
+
assert_raise(ActiveRecord::AssociationTypeMismatch) { jamis.projects << 1 }
|
186
|
+
end
|
187
|
+
|
188
|
+
def test_adding_from_the_project
|
189
|
+
jamis = Developer.find(2)
|
190
|
+
action_controller = Project.find(2)
|
191
|
+
action_controller.developers.reload
|
192
|
+
assert_equal 1, jamis.projects.size
|
193
|
+
assert_equal 1, action_controller.developers.size
|
194
|
+
|
195
|
+
action_controller.developers << jamis
|
196
|
+
|
197
|
+
assert_equal 2, jamis.projects(true).size
|
198
|
+
assert_equal 2, action_controller.developers.size
|
199
|
+
assert_equal 2, action_controller.developers(true).size
|
200
|
+
end
|
201
|
+
|
202
|
+
def test_adding_from_the_project_fixed_timestamp
|
203
|
+
jamis = Developer.find(2)
|
204
|
+
action_controller = Project.find(2)
|
205
|
+
action_controller.developers.reload
|
206
|
+
assert_equal 1, jamis.projects.size
|
207
|
+
assert_equal 1, action_controller.developers.size
|
208
|
+
updated_at = jamis.updated_at
|
209
|
+
|
210
|
+
action_controller.developers << jamis
|
211
|
+
|
212
|
+
assert_equal updated_at, jamis.updated_at
|
213
|
+
assert_equal 2, jamis.projects(true).size
|
214
|
+
assert_equal 2, action_controller.developers.size
|
215
|
+
assert_equal 2, action_controller.developers(true).size
|
216
|
+
end
|
217
|
+
|
218
|
+
def test_adding_multiple
|
219
|
+
aredridel = Developer.new("name" => "Aredridel")
|
220
|
+
aredridel.save
|
221
|
+
aredridel.projects.reload
|
222
|
+
aredridel.projects.push(Project.find(1), Project.find(2))
|
223
|
+
assert_equal 2, aredridel.projects.size
|
224
|
+
assert_equal 2, aredridel.projects(true).size
|
225
|
+
end
|
226
|
+
|
227
|
+
def test_adding_a_collection
|
228
|
+
aredridel = Developer.new("name" => "Aredridel")
|
229
|
+
aredridel.save
|
230
|
+
aredridel.projects.reload
|
231
|
+
aredridel.projects.concat([Project.find(1), Project.find(2)])
|
232
|
+
assert_equal 2, aredridel.projects.size
|
233
|
+
assert_equal 2, aredridel.projects(true).size
|
234
|
+
end
|
235
|
+
|
236
|
+
def test_adding_uses_default_values_on_join_table
|
237
|
+
ac = projects(:action_controller)
|
238
|
+
assert !developers(:jamis).projects.include?(ac)
|
239
|
+
developers(:jamis).projects << ac
|
240
|
+
|
241
|
+
assert developers(:jamis, :reload).projects.include?(ac)
|
242
|
+
project = developers(:jamis).projects.detect { |p| p == ac }
|
243
|
+
assert_equal 1, project.access_level.to_i
|
244
|
+
end
|
245
|
+
|
246
|
+
def test_habtm_attribute_access_and_respond_to
|
247
|
+
project = developers(:jamis).projects[0]
|
248
|
+
assert project.has_attribute?("name")
|
249
|
+
assert project.has_attribute?("joined_on")
|
250
|
+
assert project.has_attribute?("access_level")
|
251
|
+
assert project.respond_to?("name")
|
252
|
+
assert project.respond_to?("name=")
|
253
|
+
assert project.respond_to?("name?")
|
254
|
+
assert project.respond_to?("joined_on")
|
255
|
+
# given that the 'join attribute' won't be persisted, I don't
|
256
|
+
# think we should define the mutators
|
257
|
+
#assert project.respond_to?("joined_on=")
|
258
|
+
assert project.respond_to?("joined_on?")
|
259
|
+
assert project.respond_to?("access_level")
|
260
|
+
#assert project.respond_to?("access_level=")
|
261
|
+
assert project.respond_to?("access_level?")
|
262
|
+
end
|
263
|
+
|
264
|
+
def test_habtm_adding_before_save
|
265
|
+
no_of_devels = Developer.count
|
266
|
+
no_of_projects = Project.count
|
267
|
+
aredridel = Developer.new("name" => "Aredridel")
|
268
|
+
aredridel.projects.concat([Project.find(1), p = Project.new("name" => "Projekt")])
|
269
|
+
assert !aredridel.persisted?
|
270
|
+
assert !p.persisted?
|
271
|
+
assert aredridel.save
|
272
|
+
assert aredridel.persisted?
|
273
|
+
assert_equal no_of_devels+1, Developer.count
|
274
|
+
assert_equal no_of_projects+1, Project.count
|
275
|
+
assert_equal 2, aredridel.projects.size
|
276
|
+
assert_equal 2, aredridel.projects(true).size
|
277
|
+
end
|
278
|
+
|
279
|
+
def test_habtm_saving_multiple_relationships
|
280
|
+
new_project = Project.new("name" => "Grimetime")
|
281
|
+
amount_of_developers = 4
|
282
|
+
developers = (0...amount_of_developers).collect {|i| Developer.create(:name => "JME #{i}") }.reverse
|
283
|
+
|
284
|
+
new_project.developer_ids = [developers[0].id, developers[1].id]
|
285
|
+
new_project.developers_with_callback_ids = [developers[2].id, developers[3].id]
|
286
|
+
assert new_project.save
|
287
|
+
|
288
|
+
new_project.reload
|
289
|
+
assert_equal amount_of_developers, new_project.developers.size
|
290
|
+
assert_equal developers, new_project.developers
|
291
|
+
end
|
292
|
+
|
293
|
+
def test_habtm_unique_order_preserved
|
294
|
+
assert_equal developers(:poor_jamis, :jamis, :david), projects(:active_record).non_unique_developers
|
295
|
+
assert_equal developers(:poor_jamis, :jamis, :david), projects(:active_record).developers
|
296
|
+
end
|
297
|
+
|
298
|
+
def test_build
|
299
|
+
devel = Developer.find(1)
|
300
|
+
proj = assert_no_queries { devel.projects.build("name" => "Projekt") }
|
301
|
+
assert !devel.projects.loaded?
|
302
|
+
|
303
|
+
assert_equal devel.projects.last, proj
|
304
|
+
assert devel.projects.loaded?
|
305
|
+
|
306
|
+
assert !proj.persisted?
|
307
|
+
devel.save
|
308
|
+
assert proj.persisted?
|
309
|
+
assert_equal devel.projects.last, proj
|
310
|
+
assert_equal Developer.find(1).projects.sort_by(&:id).last, proj # prove join table is updated
|
311
|
+
end
|
312
|
+
|
313
|
+
def test_build_by_new_record
|
314
|
+
devel = Developer.new(:name => "Marcel", :salary => 75000)
|
315
|
+
proj1 = devel.projects.build(:name => "Make bed")
|
316
|
+
proj2 = devel.projects.build(:name => "Lie in it")
|
317
|
+
assert_equal devel.projects.last, proj2
|
318
|
+
assert !proj2.persisted?
|
319
|
+
devel.save
|
320
|
+
assert devel.persisted?
|
321
|
+
assert proj2.persisted?
|
322
|
+
assert_equal devel.projects.last, proj2
|
323
|
+
assert_equal Developer.find_by_name("Marcel").projects.last, proj2 # prove join table is updated
|
324
|
+
end
|
325
|
+
|
326
|
+
def test_create
|
327
|
+
devel = Developer.find(1)
|
328
|
+
proj = devel.projects.create("name" => "Projekt")
|
329
|
+
assert !devel.projects.loaded?
|
330
|
+
|
331
|
+
assert_equal devel.projects.last, proj
|
332
|
+
assert !devel.projects.loaded?
|
333
|
+
|
334
|
+
assert proj.persisted?
|
335
|
+
assert_equal Developer.find(1).projects.sort_by(&:id).last, proj # prove join table is updated
|
336
|
+
end
|
337
|
+
|
338
|
+
if current_adapter?(:IBM_DBAdapter)
|
339
|
+
def test_lob_handling
|
340
|
+
assert_nothing_raised do
|
341
|
+
Novel.connection.create_table 'novels' do |t|
|
342
|
+
t.text :story
|
343
|
+
t.string :title
|
344
|
+
end
|
345
|
+
Writer.connection.create_table 'writers' do |t|
|
346
|
+
t.string :name
|
347
|
+
end
|
348
|
+
NovelsWriter.connection.create_table 'novels_writers' do |t|
|
349
|
+
t.belongs_to :novels
|
350
|
+
t.belongs_to :writers
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
354
|
+
w = Writer.new :name => 'Praveen'
|
355
|
+
w.save!
|
356
|
+
|
357
|
+
novel_story = "This is a short and sweet story"
|
358
|
+
|
359
|
+
novel = Novel.new :story => novel_story,:title => "Cool isn't it"
|
360
|
+
novel.writers << w
|
361
|
+
novel.save!
|
362
|
+
|
363
|
+
assert_equal novel_story,Novel.find(novel.id).story
|
364
|
+
ensure
|
365
|
+
Novel.connection.drop_table 'novels' rescue nil
|
366
|
+
Writer.connection.drop_table 'writers' rescue nil
|
367
|
+
NovelsWriter.connection.drop_table 'novels_writers' rescue nil
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
def test_create_by_new_record
|
372
|
+
devel = Developer.new(:name => "Marcel", :salary => 75000)
|
373
|
+
proj1 = devel.projects.build(:name => "Make bed")
|
374
|
+
proj2 = devel.projects.build(:name => "Lie in it")
|
375
|
+
assert_equal devel.projects.last, proj2
|
376
|
+
assert !proj2.persisted?
|
377
|
+
devel.save
|
378
|
+
assert devel.persisted?
|
379
|
+
assert proj2.persisted?
|
380
|
+
assert_equal devel.projects.last, proj2
|
381
|
+
assert_equal Developer.find_by_name("Marcel").projects.last, proj2 # prove join table is updated
|
382
|
+
end
|
383
|
+
|
384
|
+
def test_creation_respects_hash_condition
|
385
|
+
# in Oracle '' is saved as null therefore need to save ' ' in not null column
|
386
|
+
post = categories(:general).post_with_conditions.build(:body => ' ')
|
387
|
+
|
388
|
+
assert post.save
|
389
|
+
assert_equal 'Yet Another Testing Title', post.title
|
390
|
+
|
391
|
+
# in Oracle '' is saved as null therefore need to save ' ' in not null column
|
392
|
+
another_post = categories(:general).post_with_conditions.create(:body => ' ')
|
393
|
+
|
394
|
+
assert another_post.persisted?
|
395
|
+
assert_equal 'Yet Another Testing Title', another_post.title
|
396
|
+
end
|
397
|
+
|
398
|
+
def test_uniq_after_the_fact
|
399
|
+
dev = developers(:jamis)
|
400
|
+
dev.projects << projects(:active_record)
|
401
|
+
dev.projects << projects(:active_record)
|
402
|
+
|
403
|
+
assert_equal 3, dev.projects.size
|
404
|
+
assert_equal 1, dev.projects.uniq.size
|
405
|
+
end
|
406
|
+
|
407
|
+
def test_uniq_before_the_fact
|
408
|
+
projects(:active_record).developers << developers(:jamis)
|
409
|
+
projects(:active_record).developers << developers(:david)
|
410
|
+
assert_equal 3, projects(:active_record, :reload).developers.size
|
411
|
+
end
|
412
|
+
|
413
|
+
def test_uniq_option_prevents_duplicate_push
|
414
|
+
project = projects(:active_record)
|
415
|
+
project.developers << developers(:jamis)
|
416
|
+
project.developers << developers(:david)
|
417
|
+
assert_equal 3, project.developers.size
|
418
|
+
|
419
|
+
project.developers << developers(:david)
|
420
|
+
project.developers << developers(:jamis)
|
421
|
+
assert_equal 3, project.developers.size
|
422
|
+
end
|
423
|
+
|
424
|
+
def test_deleting
|
425
|
+
david = Developer.find(1)
|
426
|
+
active_record = Project.find(1)
|
427
|
+
david.projects.reload
|
428
|
+
assert_equal 2, david.projects.size
|
429
|
+
assert_equal 3, active_record.developers.size
|
430
|
+
|
431
|
+
david.projects.delete(active_record)
|
432
|
+
|
433
|
+
assert_equal 1, david.projects.size
|
434
|
+
assert_equal 1, david.projects(true).size
|
435
|
+
assert_equal 2, active_record.developers(true).size
|
436
|
+
end
|
437
|
+
|
438
|
+
def test_deleting_array
|
439
|
+
david = Developer.find(1)
|
440
|
+
david.projects.reload
|
441
|
+
david.projects.delete(Project.find(:all))
|
442
|
+
assert_equal 0, david.projects.size
|
443
|
+
assert_equal 0, david.projects(true).size
|
444
|
+
end
|
445
|
+
|
446
|
+
def test_deleting_with_sql
|
447
|
+
david = Developer.find(1)
|
448
|
+
active_record = Project.find(1)
|
449
|
+
active_record.developers.reload
|
450
|
+
assert_equal 3, active_record.developers_by_sql.size
|
451
|
+
|
452
|
+
active_record.developers_by_sql.delete(david)
|
453
|
+
assert_equal 2, active_record.developers_by_sql(true).size
|
454
|
+
end
|
455
|
+
|
456
|
+
def test_deleting_array_with_sql
|
457
|
+
active_record = Project.find(1)
|
458
|
+
active_record.developers.reload
|
459
|
+
assert_equal 3, active_record.developers_by_sql.size
|
460
|
+
|
461
|
+
active_record.developers_by_sql.delete(Developer.find(:all))
|
462
|
+
assert_equal 0, active_record.developers_by_sql(true).size
|
463
|
+
end
|
464
|
+
|
465
|
+
def test_deleting_all
|
466
|
+
david = Developer.find(1)
|
467
|
+
david.projects.reload
|
468
|
+
david.projects.clear
|
469
|
+
assert_equal 0, david.projects.size
|
470
|
+
assert_equal 0, david.projects(true).size
|
471
|
+
end
|
472
|
+
|
473
|
+
def test_removing_associations_on_destroy
|
474
|
+
david = DeveloperWithBeforeDestroyRaise.find(1)
|
475
|
+
assert !david.projects.empty?
|
476
|
+
assert_raise(RuntimeError) { david.destroy }
|
477
|
+
assert david.projects.empty?
|
478
|
+
assert DeveloperWithBeforeDestroyRaise.connection.select_all("SELECT * FROM developers_projects WHERE developer_id = 1").empty?
|
479
|
+
end
|
480
|
+
|
481
|
+
def test_additional_columns_from_join_table
|
482
|
+
assert_date_from_db Date.new(2004, 10, 10), Developer.find(1).projects.first.joined_on.to_date
|
483
|
+
end
|
484
|
+
|
485
|
+
def test_destroying
|
486
|
+
david = Developer.find(1)
|
487
|
+
active_record = Project.find(1)
|
488
|
+
david.projects.reload
|
489
|
+
assert_equal 2, david.projects.size
|
490
|
+
assert_equal 3, active_record.developers.size
|
491
|
+
|
492
|
+
assert_difference "Project.count", -1 do
|
493
|
+
david.projects.destroy(active_record)
|
494
|
+
end
|
495
|
+
|
496
|
+
assert_equal 1, david.reload.projects.size
|
497
|
+
assert_equal 1, david.projects(true).size
|
498
|
+
end
|
499
|
+
|
500
|
+
def test_destroying_array
|
501
|
+
david = Developer.find(1)
|
502
|
+
david.projects.reload
|
503
|
+
|
504
|
+
assert_difference "Project.count", -Project.count do
|
505
|
+
david.projects.destroy(Project.find(:all))
|
506
|
+
end
|
507
|
+
|
508
|
+
assert_equal 0, david.reload.projects.size
|
509
|
+
assert_equal 0, david.projects(true).size
|
510
|
+
end
|
511
|
+
|
512
|
+
def test_destroy_all
|
513
|
+
david = Developer.find(1)
|
514
|
+
david.projects.reload
|
515
|
+
assert !david.projects.empty?
|
516
|
+
david.projects.destroy_all
|
517
|
+
assert david.projects.empty?
|
518
|
+
assert david.projects(true).empty?
|
519
|
+
end
|
520
|
+
|
521
|
+
def test_deprecated_push_with_attributes_was_removed
|
522
|
+
jamis = developers(:jamis)
|
523
|
+
assert_raise(NoMethodError) do
|
524
|
+
jamis.projects.push_with_attributes(projects(:action_controller), :joined_on => Date.today)
|
525
|
+
end
|
526
|
+
end
|
527
|
+
|
528
|
+
def test_associations_with_conditions
|
529
|
+
assert_equal 3, projects(:active_record).developers.size
|
530
|
+
assert_equal 1, projects(:active_record).developers_named_david.size
|
531
|
+
assert_equal 1, projects(:active_record).developers_named_david_with_hash_conditions.size
|
532
|
+
|
533
|
+
assert_equal developers(:david), projects(:active_record).developers_named_david.find(developers(:david).id)
|
534
|
+
assert_equal developers(:david), projects(:active_record).developers_named_david_with_hash_conditions.find(developers(:david).id)
|
535
|
+
assert_equal developers(:david), projects(:active_record).salaried_developers.find(developers(:david).id)
|
536
|
+
|
537
|
+
projects(:active_record).developers_named_david.clear
|
538
|
+
assert_equal 2, projects(:active_record, :reload).developers.size
|
539
|
+
end
|
540
|
+
|
541
|
+
def test_find_in_association
|
542
|
+
# Using sql
|
543
|
+
assert_equal developers(:david), projects(:active_record).developers.find(developers(:david).id), "SQL find"
|
544
|
+
|
545
|
+
# Using ruby
|
546
|
+
active_record = projects(:active_record)
|
547
|
+
active_record.developers.reload
|
548
|
+
assert_equal developers(:david), active_record.developers.find(developers(:david).id), "Ruby find"
|
549
|
+
end
|
550
|
+
|
551
|
+
def test_include_uses_array_include_after_loaded
|
552
|
+
project = projects(:active_record)
|
553
|
+
project.developers.class # force load target
|
554
|
+
|
555
|
+
developer = project.developers.first
|
556
|
+
|
557
|
+
assert_no_queries do
|
558
|
+
assert project.developers.loaded?
|
559
|
+
assert project.developers.include?(developer)
|
560
|
+
end
|
561
|
+
end
|
562
|
+
|
563
|
+
def test_include_checks_if_record_exists_if_target_not_loaded
|
564
|
+
project = projects(:active_record)
|
565
|
+
developer = project.developers.first
|
566
|
+
|
567
|
+
project.reload
|
568
|
+
assert ! project.developers.loaded?
|
569
|
+
assert_queries(1) do
|
570
|
+
assert project.developers.include?(developer)
|
571
|
+
end
|
572
|
+
assert ! project.developers.loaded?
|
573
|
+
end
|
574
|
+
|
575
|
+
def test_include_returns_false_for_non_matching_record_to_verify_scoping
|
576
|
+
project = projects(:active_record)
|
577
|
+
developer = Developer.create :name => "Bryan", :salary => 50_000
|
578
|
+
|
579
|
+
assert ! project.developers.loaded?
|
580
|
+
assert ! project.developers.include?(developer)
|
581
|
+
end
|
582
|
+
|
583
|
+
def test_find_in_association_with_custom_finder_sql
|
584
|
+
assert_equal developers(:david), projects(:active_record).developers_with_finder_sql.find(developers(:david).id), "SQL find"
|
585
|
+
|
586
|
+
active_record = projects(:active_record)
|
587
|
+
active_record.developers_with_finder_sql.reload
|
588
|
+
assert_equal developers(:david), active_record.developers_with_finder_sql.find(developers(:david).id), "Ruby find"
|
589
|
+
end
|
590
|
+
|
591
|
+
def test_find_in_association_with_custom_finder_sql_and_multiple_interpolations
|
592
|
+
# interpolate once:
|
593
|
+
assert_equal [developers(:david), developers(:jamis), developers(:poor_jamis)], projects(:active_record).developers_with_finder_sql, "first interpolation"
|
594
|
+
# interpolate again, for a different project id
|
595
|
+
assert_equal [developers(:david)], projects(:action_controller).developers_with_finder_sql, "second interpolation"
|
596
|
+
end
|
597
|
+
|
598
|
+
def test_find_in_association_with_custom_finder_sql_and_string_id
|
599
|
+
assert_equal developers(:david), projects(:active_record).developers_with_finder_sql.find(developers(:david).id.to_s), "SQL find"
|
600
|
+
end
|
601
|
+
|
602
|
+
def test_find_with_merged_options
|
603
|
+
assert_equal 1, projects(:active_record).limited_developers.size
|
604
|
+
assert_equal 1, projects(:active_record).limited_developers.find(:all).size
|
605
|
+
assert_equal 3, projects(:active_record).limited_developers.find(:all, :limit => nil).size
|
606
|
+
end
|
607
|
+
|
608
|
+
def test_dynamic_find_should_respect_association_order
|
609
|
+
# Developers are ordered 'name DESC, id DESC'
|
610
|
+
low_id_jamis = developers(:jamis)
|
611
|
+
middle_id_jamis = developers(:poor_jamis)
|
612
|
+
high_id_jamis = projects(:active_record).developers.create(:name => 'Jamis')
|
613
|
+
|
614
|
+
assert_equal high_id_jamis, projects(:active_record).developers.find(:first, :conditions => "name = 'Jamis'")
|
615
|
+
assert_equal high_id_jamis, projects(:active_record).developers.find_by_name('Jamis')
|
616
|
+
end
|
617
|
+
|
618
|
+
def test_dynamic_find_all_should_respect_association_order
|
619
|
+
# Developers are ordered 'name DESC, id DESC'
|
620
|
+
low_id_jamis = developers(:jamis)
|
621
|
+
middle_id_jamis = developers(:poor_jamis)
|
622
|
+
high_id_jamis = projects(:active_record).developers.create(:name => 'Jamis')
|
623
|
+
|
624
|
+
assert_equal [high_id_jamis, middle_id_jamis, low_id_jamis], projects(:active_record).developers.find(:all, :conditions => "name = 'Jamis'")
|
625
|
+
assert_equal [high_id_jamis, middle_id_jamis, low_id_jamis], projects(:active_record).developers.find_all_by_name('Jamis')
|
626
|
+
end
|
627
|
+
|
628
|
+
def test_find_should_append_to_association_order
|
629
|
+
ordered_developers = projects(:active_record).developers.order('projects.id')
|
630
|
+
assert_equal ['developers.name desc, developers.id desc', 'projects.id'], ordered_developers.order_values
|
631
|
+
end
|
632
|
+
|
633
|
+
def test_dynamic_find_all_should_respect_association_limit
|
634
|
+
assert_equal 1, projects(:active_record).limited_developers.find(:all, :conditions => "name = 'Jamis'").length
|
635
|
+
assert_equal 1, projects(:active_record).limited_developers.find_all_by_name('Jamis').length
|
636
|
+
end
|
637
|
+
|
638
|
+
def test_dynamic_find_all_order_should_override_association_limit
|
639
|
+
assert_equal 2, projects(:active_record).limited_developers.find(:all, :conditions => "name = 'Jamis'", :limit => 9_000).length
|
640
|
+
assert_equal 2, projects(:active_record).limited_developers.find_all_by_name('Jamis', :limit => 9_000).length
|
641
|
+
end
|
642
|
+
|
643
|
+
def test_dynamic_find_all_should_respect_readonly_access
|
644
|
+
projects(:active_record).readonly_developers.each { |d| assert_raise(ActiveRecord::ReadOnlyRecord) { d.save! } if d.valid?}
|
645
|
+
projects(:active_record).readonly_developers.each { |d| d.readonly? }
|
646
|
+
end
|
647
|
+
|
648
|
+
def test_new_with_values_in_collection
|
649
|
+
jamis = DeveloperForProjectWithAfterCreateHook.find_by_name('Jamis')
|
650
|
+
david = DeveloperForProjectWithAfterCreateHook.find_by_name('David')
|
651
|
+
project = ProjectWithAfterCreateHook.new(:name => "Cooking with Bertie")
|
652
|
+
project.developers << jamis
|
653
|
+
project.save!
|
654
|
+
project.reload
|
655
|
+
|
656
|
+
assert project.developers.include?(jamis)
|
657
|
+
assert project.developers.include?(david)
|
658
|
+
end
|
659
|
+
|
660
|
+
def test_find_in_association_with_options
|
661
|
+
developers = projects(:active_record).developers.all
|
662
|
+
assert_equal 3, developers.size
|
663
|
+
|
664
|
+
assert_equal developers(:poor_jamis), projects(:active_record).developers.where("salary < 10000").first
|
665
|
+
end
|
666
|
+
|
667
|
+
def test_replace_with_less
|
668
|
+
david = developers(:david)
|
669
|
+
david.projects = [projects(:action_controller)]
|
670
|
+
assert david.save
|
671
|
+
assert_equal 1, david.projects.length
|
672
|
+
end
|
673
|
+
|
674
|
+
def test_replace_with_new
|
675
|
+
david = developers(:david)
|
676
|
+
david.projects = [projects(:action_controller), Project.new("name" => "ActionWebSearch")]
|
677
|
+
david.save
|
678
|
+
assert_equal 2, david.projects.length
|
679
|
+
assert !david.projects.include?(projects(:active_record))
|
680
|
+
end
|
681
|
+
|
682
|
+
def test_replace_on_new_object
|
683
|
+
new_developer = Developer.new("name" => "Matz")
|
684
|
+
new_developer.projects = [projects(:action_controller), Project.new("name" => "ActionWebSearch")]
|
685
|
+
new_developer.save
|
686
|
+
assert_equal 2, new_developer.projects.length
|
687
|
+
end
|
688
|
+
|
689
|
+
def test_consider_type
|
690
|
+
developer = Developer.find(:first)
|
691
|
+
special_project = SpecialProject.create("name" => "Special Project")
|
692
|
+
|
693
|
+
other_project = developer.projects.first
|
694
|
+
developer.special_projects << special_project
|
695
|
+
developer.reload
|
696
|
+
|
697
|
+
assert developer.projects.include?(special_project)
|
698
|
+
assert developer.special_projects.include?(special_project)
|
699
|
+
assert !developer.special_projects.include?(other_project)
|
700
|
+
end
|
701
|
+
|
702
|
+
def test_update_attributes_after_push_without_duplicate_join_table_rows
|
703
|
+
developer = Developer.new("name" => "Kano")
|
704
|
+
project = SpecialProject.create("name" => "Special Project")
|
705
|
+
assert developer.save
|
706
|
+
developer.projects << project
|
707
|
+
developer.update_attribute("name", "Bruza")
|
708
|
+
assert_equal 1, Developer.connection.select_value(<<-end_sql).to_i
|
709
|
+
SELECT count(*) FROM developers_projects
|
710
|
+
WHERE project_id = #{project.id}
|
711
|
+
AND developer_id = #{developer.id}
|
712
|
+
end_sql
|
713
|
+
end
|
714
|
+
|
715
|
+
def test_updating_attributes_on_non_rich_associations
|
716
|
+
welcome = categories(:technology).posts.first
|
717
|
+
welcome.title = "Something else"
|
718
|
+
assert welcome.save!
|
719
|
+
end
|
720
|
+
|
721
|
+
def test_habtm_respects_select
|
722
|
+
categories(:technology).select_testing_posts(true).each do |o|
|
723
|
+
assert_respond_to o, :correctness_marker
|
724
|
+
end
|
725
|
+
assert_respond_to categories(:technology).select_testing_posts.find(:first), :correctness_marker
|
726
|
+
end
|
727
|
+
|
728
|
+
def test_updating_attributes_on_rich_associations
|
729
|
+
david = projects(:action_controller).developers.first
|
730
|
+
david.name = "DHH"
|
731
|
+
assert_raise(ActiveRecord::ReadOnlyRecord) { david.save! }
|
732
|
+
end
|
733
|
+
|
734
|
+
def test_updating_attributes_on_rich_associations_with_limited_find_from_reflection
|
735
|
+
david = projects(:action_controller).selected_developers.first
|
736
|
+
david.name = "DHH"
|
737
|
+
assert_nothing_raised { david.save! }
|
738
|
+
end
|
739
|
+
|
740
|
+
|
741
|
+
def test_updating_attributes_on_rich_associations_with_limited_find
|
742
|
+
david = projects(:action_controller).developers.find(:all, :select => "developers.*").first
|
743
|
+
david.name = "DHH"
|
744
|
+
assert david.save!
|
745
|
+
end
|
746
|
+
|
747
|
+
def test_join_table_alias
|
748
|
+
assert_equal 3, Developer.find(:all, :include => {:projects => :developers}, :conditions => 'developers_projects_join.joined_on IS NOT NULL').size
|
749
|
+
end
|
750
|
+
|
751
|
+
def test_join_with_group
|
752
|
+
group = Developer.columns.inject([]) do |g, c|
|
753
|
+
g << "developers.#{c.name}"
|
754
|
+
g << "developers_projects_2.#{c.name}"
|
755
|
+
end
|
756
|
+
Project.columns.each { |c| group << "projects.#{c.name}" }
|
757
|
+
|
758
|
+
assert_equal 3, Developer.find(:all, :include => {:projects => :developers}, :conditions => 'developers_projects_join.joined_on IS NOT NULL', :group => group.join(",")).size
|
759
|
+
end
|
760
|
+
|
761
|
+
def test_find_grouped
|
762
|
+
all_posts_from_category1 = Post.find(:all, :conditions => "category_id = 1", :joins => :categories)
|
763
|
+
grouped_posts_of_category1 = Post.find(:all, :conditions => "category_id = 1", :group => "author_id", :select => 'count(posts.id) as posts_count', :joins => :categories)
|
764
|
+
assert_equal 4, all_posts_from_category1.size
|
765
|
+
assert_equal 1, grouped_posts_of_category1.size
|
766
|
+
end
|
767
|
+
|
768
|
+
def test_find_scoped_grouped
|
769
|
+
assert_equal 4, categories(:general).posts_grouped_by_title.size
|
770
|
+
assert_equal 1, categories(:technology).posts_grouped_by_title.size
|
771
|
+
end
|
772
|
+
|
773
|
+
def test_find_scoped_grouped_having
|
774
|
+
assert_equal 2, projects(:active_record).well_payed_salary_groups.size
|
775
|
+
assert projects(:active_record).well_payed_salary_groups.all? { |g| g.salary > 10000 }
|
776
|
+
end
|
777
|
+
|
778
|
+
def test_get_ids
|
779
|
+
assert_equal projects(:active_record, :action_controller).map(&:id).sort, developers(:david).project_ids.sort
|
780
|
+
assert_equal [projects(:active_record).id], developers(:jamis).project_ids
|
781
|
+
end
|
782
|
+
|
783
|
+
def test_get_ids_for_loaded_associations
|
784
|
+
developer = developers(:david)
|
785
|
+
developer.projects(true)
|
786
|
+
assert_queries(0) do
|
787
|
+
developer.project_ids
|
788
|
+
developer.project_ids
|
789
|
+
end
|
790
|
+
end
|
791
|
+
|
792
|
+
def test_get_ids_for_unloaded_associations_does_not_load_them
|
793
|
+
developer = developers(:david)
|
794
|
+
assert !developer.projects.loaded?
|
795
|
+
assert_equal projects(:active_record, :action_controller).map(&:id).sort, developer.project_ids.sort
|
796
|
+
assert !developer.projects.loaded?
|
797
|
+
end
|
798
|
+
|
799
|
+
def test_assign_ids
|
800
|
+
developer = Developer.new("name" => "Joe")
|
801
|
+
developer.project_ids = projects(:active_record, :action_controller).map(&:id)
|
802
|
+
developer.save
|
803
|
+
developer.reload
|
804
|
+
assert_equal 2, developer.projects.length
|
805
|
+
assert_equal [projects(:active_record), projects(:action_controller)].map(&:id).sort, developer.project_ids.sort
|
806
|
+
end
|
807
|
+
|
808
|
+
def test_assign_ids_ignoring_blanks
|
809
|
+
developer = Developer.new("name" => "Joe")
|
810
|
+
developer.project_ids = [projects(:active_record).id, nil, projects(:action_controller).id, '']
|
811
|
+
developer.save
|
812
|
+
developer.reload
|
813
|
+
assert_equal 2, developer.projects.length
|
814
|
+
assert_equal [projects(:active_record), projects(:action_controller)].map(&:id).sort, developer.project_ids.sort
|
815
|
+
end
|
816
|
+
|
817
|
+
def test_scoped_find_on_through_association_doesnt_return_read_only_records
|
818
|
+
tag = Post.find(1).tags.find_by_name("General")
|
819
|
+
|
820
|
+
assert_nothing_raised do
|
821
|
+
tag.save!
|
822
|
+
end
|
823
|
+
end
|
824
|
+
|
825
|
+
def test_has_many_through_polymorphic_has_manys_works
|
826
|
+
assert_equal [10, 20].to_set, pirates(:redbeard).treasure_estimates.map(&:price).to_set
|
827
|
+
end
|
828
|
+
|
829
|
+
def test_symbols_as_keys
|
830
|
+
developer = DeveloperWithSymbolsForKeys.new(:name => 'David')
|
831
|
+
project = ProjectWithSymbolsForKeys.new(:name => 'Rails Testing')
|
832
|
+
project.developers << developer
|
833
|
+
project.save!
|
834
|
+
|
835
|
+
assert_equal 1, project.developers.size
|
836
|
+
assert_equal 1, developer.projects.size
|
837
|
+
assert_equal developer, project.developers.find(:first)
|
838
|
+
assert_equal project, developer.projects.find(:first)
|
839
|
+
end
|
840
|
+
|
841
|
+
def test_self_referential_habtm_without_foreign_key_set_should_raise_exception
|
842
|
+
assert_raise(ActiveRecord::HasAndBelongsToManyAssociationForeignKeyNeeded) {
|
843
|
+
Member.class_eval do
|
844
|
+
has_and_belongs_to_many :friends, :class_name => "Member", :join_table => "member_friends"
|
845
|
+
end
|
846
|
+
}
|
847
|
+
end
|
848
|
+
|
849
|
+
unless current_adapter?(:IBM_DBAdapter) #refer SQL214n
|
850
|
+
def test_dynamic_find_should_respect_association_include
|
851
|
+
# SQL error in sort clause if :include is not included
|
852
|
+
# due to Unknown column 'authors.id'
|
853
|
+
assert Category.find(1).posts_with_authors_sorted_by_author_id.find_by_title('Welcome to the weblog')
|
854
|
+
end
|
855
|
+
end
|
856
|
+
|
857
|
+
def test_counting_on_habtm_association_and_not_array
|
858
|
+
david = Developer.find(1)
|
859
|
+
# Extra parameter just to make sure we aren't falling back to
|
860
|
+
# Array#count in Ruby >=1.8.7, which would raise an ArgumentError
|
861
|
+
assert_nothing_raised { david.projects.count(:all, :conditions => '1=1') }
|
862
|
+
end
|
863
|
+
|
864
|
+
def test_count
|
865
|
+
david = Developer.find(1)
|
866
|
+
assert_equal 2, david.projects.count
|
867
|
+
end
|
868
|
+
|
869
|
+
def test_count_with_counter_sql
|
870
|
+
developer = DeveloperWithCounterSQL.create(:name => 'tekin')
|
871
|
+
developer.project_ids = [projects(:active_record).id]
|
872
|
+
developer.save
|
873
|
+
developer.reload
|
874
|
+
assert_equal 1, developer.projects.count
|
875
|
+
end
|
876
|
+
|
877
|
+
unless current_adapter?(:PostgreSQLAdapter)
|
878
|
+
def test_count_with_finder_sql
|
879
|
+
assert_equal 3, projects(:active_record).developers_with_finder_sql.count
|
880
|
+
assert_equal 3, projects(:active_record).developers_with_multiline_finder_sql.count
|
881
|
+
end
|
882
|
+
end
|
883
|
+
|
884
|
+
def test_association_proxy_transaction_method_starts_transaction_in_association_class
|
885
|
+
Post.expects(:transaction)
|
886
|
+
Category.find(:first).posts.transaction do
|
887
|
+
# nothing
|
888
|
+
end
|
889
|
+
end
|
890
|
+
|
891
|
+
def test_caching_of_columns
|
892
|
+
david = Developer.find(1)
|
893
|
+
# clear cache possibly created by other tests
|
894
|
+
david.projects.reset_column_information
|
895
|
+
assert_queries(0) { david.projects.columns; david.projects.columns }
|
896
|
+
# and again to verify that reset_column_information clears the cache correctly
|
897
|
+
david.projects.reset_column_information
|
898
|
+
assert_queries(0) { david.projects.columns; david.projects.columns }
|
899
|
+
end
|
900
|
+
|
901
|
+
def test_attributes_are_being_set_when_initialized_from_habm_association_with_where_clause
|
902
|
+
new_developer = projects(:action_controller).developers.where(:name => "Marcelo").build
|
903
|
+
assert_equal new_developer.name, "Marcelo"
|
904
|
+
end
|
905
|
+
|
906
|
+
def test_attributes_are_being_set_when_initialized_from_habm_association_with_multiple_where_clauses
|
907
|
+
new_developer = projects(:action_controller).developers.where(:name => "Marcelo").where(:salary => 90_000).build
|
908
|
+
assert_equal new_developer.name, "Marcelo"
|
909
|
+
assert_equal new_developer.salary, 90_000
|
910
|
+
end
|
911
|
+
|
912
|
+
def test_include_method_in_has_and_belongs_to_many_association_should_return_true_for_instance_added_with_build
|
913
|
+
project = Project.new
|
914
|
+
developer = project.developers.build
|
915
|
+
assert project.developers.include?(developer)
|
916
|
+
end
|
917
|
+
end
|