delineate 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/spec/database.yml ADDED
@@ -0,0 +1,17 @@
1
+ sqlite3:
2
+ adapter: sqlite3
3
+ database: ':memory:'
4
+
5
+ mysql:
6
+ adapter: mysql
7
+ hostname: localhost
8
+ username: root
9
+ password:
10
+ database: delineate_test
11
+
12
+ postgresql:
13
+ adapter: postgresql
14
+ hostname: localhost
15
+ username: postgres
16
+ password:
17
+ database: delineate_test
@@ -0,0 +1,662 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+ require 'active_support/json.rb'
3
+ require 'active_support/xml_mini.rb'
4
+
5
+ describe "Attribute Map declaration (attributes)" do
6
+ it "should require a map name" do
7
+ running {
8
+ Post.map_attributes do
9
+ attribute :post_id, :using => :id
10
+ end
11
+ }.should raise_error(ArgumentError)
12
+ end
13
+
14
+ it "should allow all valid attribute options" do
15
+ running {
16
+ Post.map_attributes :test do
17
+ attribute :name, :using => :attr, :access => :rw, :optional => true, :read => lambda{}, :write => lambda{}
18
+ end
19
+ }.should_not raise_error
20
+ end
21
+
22
+ it "should raise an error for invalid attribute options" do
23
+ running {
24
+ Post.map_attributes :test do
25
+ attribute :name, :hello => true
26
+ end
27
+ }.should raise_error(ArgumentError)
28
+ end
29
+
30
+ it "should raise an error for unknown attribute" do
31
+ Post.map_attributes :test do
32
+ attribute :xxx, :access => :ro
33
+ end
34
+
35
+ p = Post.new
36
+ expect {p.test_attributes}.to raise_error(NoMethodError)
37
+ end
38
+
39
+ it "should error for writeable attribute not declared as attribute_accessible" do
40
+ running {
41
+ Post.map_attributes :test do
42
+ attribute :xxx
43
+ end
44
+ }.should raise_error(RuntimeError, /Expected 'attr_accessible :xxx'/)
45
+ end
46
+
47
+ it "should allow all valid access options" do
48
+ running {
49
+ Post.attr_accessible(:created_at)
50
+ Post.map_attributes :test do
51
+ attribute :title, :access => :ro
52
+ attribute :content, :access => :rw
53
+ attribute :created_at, :access => :w
54
+ end
55
+ }.should_not raise_error
56
+ end
57
+
58
+ it "should not allow :write option when access is :ro" do
59
+ running {
60
+ Post.map_attributes :test do
61
+ attribute :name, :access => :ro, :write => lambda{}
62
+ end
63
+ }.should raise_error(ArgumentError)
64
+ end
65
+
66
+ it "should raise an error for invalid access option value" do
67
+ running {
68
+ Post.map_attributes :test do
69
+ attribute :name, :access => :ddd
70
+ end
71
+ }.should raise_error(ArgumentError)
72
+ end
73
+
74
+ it "should automatically name an attribute read/write lamda" do
75
+ Post.map_attributes :test do
76
+ attribute :summary, :read => lambda {|p| p.instance_variable_get(:@test)},
77
+ :write => lambda {|p, v| p.instance_variable_set(:@test, v)}
78
+ end
79
+
80
+ p = Post.new
81
+ p.summary_test = "This is a test"
82
+ p.summary_test.should == "This is a test"
83
+ expect(p.test_attributes).to include(:summary => 'This is a test')
84
+ end
85
+
86
+ it "should honor the model_attr name for an attribute read/write lamda" do
87
+ Post.map_attributes :test do
88
+ attribute :name, :using => :test_name, :access => :ro, :read => lambda{|p| "This is a test"}
89
+ end
90
+ p = Post.new
91
+ p.test_name.should == "This is a test"
92
+ end
93
+
94
+ end
95
+
96
+ describe "Attribute Map declaration (associations)" do
97
+ before(:all) do
98
+ reload_model_classes!
99
+ end
100
+
101
+ it "should raise an error for an undefined association" do
102
+ running {
103
+ Post.map_attributes :test do
104
+ association :hello
105
+ end
106
+ }.should raise_error(ArgumentError)
107
+ end
108
+
109
+ it "should raise an error for invalid association options" do
110
+ running {
111
+ Post.map_attributes :test do
112
+ association :comments, :hello => true
113
+ end
114
+ }.should raise_error(ArgumentError)
115
+ end
116
+
117
+ it "should allow all valid association options" do
118
+ running {
119
+ Post.attr_accessible(:name)
120
+ Post.map_attributes :test do
121
+ attribute :name
122
+ association :comments, :using => :comments, :override => :merge, :polymorphic => false, :access => :rw,
123
+ :optional => true
124
+ end
125
+ }.should_not raise_error
126
+ end
127
+
128
+ it "should raise an error for invalid access option value" do
129
+ running {
130
+ Post.map_attributes :test do
131
+ association :comments, :access => :bad
132
+ end
133
+ }.should raise_error(ArgumentError)
134
+ end
135
+
136
+ it "should raise an error for invalid :override option value" do
137
+ running {
138
+ Reply.map_attributes :test, :override => true do
139
+ association :comments
140
+ end
141
+ }.should raise_error(ArgumentError)
142
+ end
143
+
144
+ it "should allow :override for STI subclass" do
145
+ running {
146
+ Reply.map_attributes :test, :override => :replace do
147
+ attribute :type
148
+ end
149
+ }.should_not raise_error
150
+ end
151
+
152
+ it "should disallow :override for non-STI subclass" do
153
+ running {
154
+ Comment.map_attributes :test, :override => :replace do
155
+ attribute :type
156
+ end
157
+ }.should raise_error(ArgumentError)
158
+ end
159
+
160
+ it "should raise an error for :replace with no specs" do
161
+ running {
162
+ Post.map_attributes :test do
163
+ association :comments, :override => :replace do
164
+ end
165
+ end
166
+ }.should raise_error(ArgumentError)
167
+ end
168
+
169
+ it "should not allow circular merge references" do
170
+ running {
171
+ Comment.map_attributes :test do
172
+ attribute :content
173
+ association :post, :optional => true do
174
+ attribute :content
175
+ end
176
+ end
177
+
178
+ Post.map_attributes :test do
179
+ attribute :title
180
+ association :comments do
181
+ attribute :commentor, :access => :ro
182
+ end
183
+ end
184
+ }.should_not raise_error
185
+
186
+ running {Post.attribute_map(:test).send('resolve!')}.should raise_error(RuntimeError, /circular merge/)
187
+ end
188
+
189
+ it "should allow circular non-merge references" do
190
+ running {
191
+ Comment.map_attributes :test do
192
+ attribute :content
193
+ association :post, :access => :ro, :optional => true, :override => :replace do
194
+ attribute :title
195
+ attribute :content
196
+ end
197
+ end
198
+
199
+ Post.map_attributes :test do
200
+ attribute :title
201
+ association :comments do
202
+ attribute :commentor, :access => :ro
203
+ end
204
+ end
205
+ }.should_not raise_error
206
+
207
+ running {Post.attribute_map(:test).send('resolve!')}.should_not raise_error
208
+
209
+
210
+
211
+ c = Comment.new(:content => "This is the content", :commentor => 'John Q Public')
212
+ p = Post.new(:title => 'This is the title')
213
+ c.post = p
214
+ p.comments = [c]
215
+
216
+ expected_result = {:title=>"This is the title",
217
+ :comments=>[{:content=>"This is the content", :commentor=>"John Q Public", :post=>{:title=>"This is the title", :content=>nil}}]
218
+ }
219
+ expect(p.test_attributes(:include => {:comments => {:include => :post}})).to eq(expected_result)
220
+ end
221
+
222
+ it "should process replacing association's map" do
223
+ running {
224
+ Comment.attr_accessible(:test)
225
+ Comment.map_attributes :test do
226
+ attribute :content
227
+ attribute :commentor
228
+ association :post, :optional => true
229
+ end
230
+
231
+ Post.map_attributes :test do
232
+ association :comments, :override => :replace do
233
+ attribute :test
234
+ attribute :commentor, :access => :ro
235
+ end
236
+ end
237
+ }.should_not raise_error
238
+ Post.attribute_map(:test).send('resolve!')
239
+
240
+ Post.attribute_map(:test).associations[:comments][:attr_map].should_not be_nil
241
+ Post.attribute_map(:test).associations[:comments][:attr_map].associations.has_key?(:post).should be_false
242
+ Post.attribute_map(:test).associations[:comments][:attr_map].attributes.should have_key(:test)
243
+ Post.attribute_map(:test).associations[:comments][:attr_map].attributes.should_not have_key(:content)
244
+ Post.attribute_map(:test).associations[:comments][:attr_map].attributes.should have_key(:commentor)
245
+ Post.attribute_map(:test).associations[:comments][:attr_map].attributes[:commentor][:access].should == :ro
246
+ end
247
+
248
+ it "should process merging association's map" do
249
+ running {
250
+ Comment.attr_accessible(:test)
251
+ Comment.map_attributes :test do
252
+ attribute :content
253
+ attribute :commentor, :access => :ro
254
+ association :post, :optional => true
255
+ end
256
+
257
+ Post.map_attributes :test do
258
+ association :comments, :override => :merge do
259
+ attribute :test
260
+ attribute :commentor
261
+ end
262
+ end
263
+ }.should_not raise_error
264
+ Post.attribute_map(:test).send('resolve!')
265
+
266
+ Post.attribute_map(:test).associations[:comments][:attr_map].should_not be_nil
267
+ Post.attribute_map(:test).associations[:comments][:attr_map].associations.size.should == 1
268
+ Post.attribute_map(:test).associations[:comments][:attr_map].attributes.should have_key(:test)
269
+ Post.attribute_map(:test).associations[:comments][:attr_map].attributes.should have_key(:content)
270
+ Post.attribute_map(:test).associations[:comments][:attr_map].attributes.should have_key(:commentor)
271
+ Post.attribute_map(:test).associations[:comments][:attr_map].attributes[:commentor][:access].should_not == :ro
272
+ Post.attribute_map(:test).associations[:comments][:attr_map].associations.should have_key(:post)
273
+ end
274
+
275
+ it "should use STI base class map in a subclass" do
276
+ running {
277
+ Post.map_attributes :test do
278
+ attribute :title
279
+ end
280
+ Comment.map_attributes :test do
281
+ attribute :content
282
+ attribute :commentor, :access => :ro
283
+ association :post, :optional => true
284
+ end
285
+ Reply.map_attributes :test do
286
+ attribute :type
287
+ end
288
+ }.should_not raise_error
289
+ Reply.attribute_map(:test).send('resolve!')
290
+
291
+ Reply.attribute_map(:test).associations[:post].should_not be_nil
292
+ Reply.attribute_map(:test).attributes.should have_key(:type)
293
+ Reply.attribute_map(:test).attributes.should have_key(:content)
294
+ Reply.attribute_map(:test).attributes.should have_key(:commentor)
295
+ end
296
+
297
+ it "should override STI base class map in a subclass when specified" do
298
+ running {
299
+ Comment.map_attributes :test do
300
+ attribute :content
301
+ attribute :commentor, :access => :ro
302
+ association :post, :optional => true
303
+ end
304
+
305
+ Reply.map_attributes :test, :override => :replace do
306
+ attribute :type
307
+ end
308
+ }.should_not raise_error
309
+ Reply.attribute_map(:test).send('resolve!')
310
+
311
+ Reply.attribute_map(:test).associations[:post].should be_nil
312
+ Reply.attribute_map(:test).attributes.should have_key(:type)
313
+ Reply.attribute_map(:test).attributes.should_not have_key(:content)
314
+ Reply.attribute_map(:test).attributes.should_not have_key(:commentor)
315
+ end
316
+
317
+ end
318
+
319
+ describe "AttributeMap Serializer" do
320
+ it "should retrieve attributes as a hash (omitting optional)" do
321
+ p = Post.first
322
+ attrs = p.api_attributes
323
+
324
+ attrs.keys.should == [:id, :title, :content, :created_at, :author, :topics]
325
+ attrs[:content].should == "This is the content for post 1"
326
+ attrs[:author].keys.should == [:id, :first_name, :last_name, :name, :email]
327
+ attrs[:author][:name].should == 'Tom Smith'
328
+ attrs[:author].should_not have_key(:posts)
329
+ attrs[:topics].should have(2).items
330
+ end
331
+
332
+ it "should retrieve attributes as json" do
333
+ p = Post.first
334
+ attrs = p.mapped_attributes(:api, :json)
335
+ attrs.should be_a_kind_of(String)
336
+ attrs = ActiveSupport::JSON.decode(attrs).symbolize_keys
337
+
338
+ (attrs.keys - [:id, :title, :content, :created_at, :author, :topics]).should be_empty
339
+ ([:id, :title, :content, :created_at, :author, :topics] - attrs.keys).should be_empty
340
+ attrs[:content].should == "This is the content for post 1"
341
+ attrs[:author].symbolize_keys!
342
+ (attrs[:author].keys - [:id, :first_name, :last_name, :name, :email]).should be_empty
343
+ ([:id, :first_name, :last_name, :name, :email] - attrs[:author].keys).should be_empty
344
+ attrs[:author][:name].should == 'Tom Smith'
345
+ attrs[:author].should_not have_key(:posts)
346
+ attrs[:topics].should have(2).items
347
+ end
348
+
349
+ it "should retrieve attributes as xml" do
350
+ p = Post.first
351
+ attrs = p.mapped_attributes(:api, :xml, :root => 'response', :dasherize => false)
352
+ attrs.should be_a_kind_of(String)
353
+ attrs = Hash.from_xml(attrs)['response'].symbolize_keys
354
+
355
+ (attrs.keys - [:id, :title, :content, :created_at, :author, :topics]).should be_empty
356
+ ([:id, :title, :content, :created_at, :author, :topics] - attrs.keys).should be_empty
357
+ attrs[:content].should == "This is the content for post 1"
358
+ attrs[:author].symbolize_keys!
359
+ (attrs[:author].keys - [:id, :first_name, :last_name, :name, :email]).should be_empty
360
+ ([:id, :first_name, :last_name, :name, :email] - attrs[:author].keys).should be_empty
361
+ attrs[:author][:name].should == 'Tom Smith'
362
+ attrs[:author].should_not have_key(:posts)
363
+ attrs[:topics].should have(2).items
364
+ end
365
+
366
+ it "should raise an error if a specified association does not have a corresponding map" do
367
+ reload_model_classes!
368
+
369
+ Post.map_attributes :test do
370
+ association :comments
371
+ end
372
+ running {
373
+ Post.first.test_attributes
374
+ }.should raise_error(RuntimeError, /Cannot resolve map/)
375
+ end
376
+
377
+ it "should honor the :only option" do
378
+ p = Post.first
379
+
380
+ attrs = p.api_attributes(:only => :id)
381
+ attrs.keys.should == [:id]
382
+
383
+ attrs = p.api_attributes(:only => [:id, :author])
384
+ attrs.keys.should == [:id, :author]
385
+ attrs[:author].keys.should == [:id, :first_name, :last_name, :name, :email]
386
+ end
387
+
388
+ it "should honor the :except option" do
389
+ p = Post.first
390
+ attrs = p.api_attributes(:except => :id)
391
+
392
+ attrs.keys.should == [:title, :content, :created_at, :author, :topics]
393
+ attrs[:author].keys.should == [:id, :first_name, :last_name, :name, :email]
394
+
395
+ attrs = p.api_attributes(:except => [:id, :title])
396
+ attrs.keys.should == [:content, :created_at, :author, :topics]
397
+ attrs[:author].keys.should == [:id, :first_name, :last_name, :name, :email]
398
+ end
399
+
400
+ it "should let :only take precendence over :except" do
401
+ p = Post.first
402
+ attrs = p.api_attributes(:only => [:id, :title], :except => :title)
403
+
404
+ attrs.keys.should == [:id, :title]
405
+ end
406
+
407
+ it "should let :include specify optional attributes" do
408
+ p = Post.first
409
+
410
+ attrs = p.api_attributes(:include => :heavy_attr)
411
+ attrs.keys.should == [:id, :title, :content, :created_at, :heavy_attr, :author, :topics]
412
+ end
413
+
414
+ it "should allow specifying an unknown :include" do
415
+ p = Post.first
416
+
417
+ attrs = p.api_attributes(:include => :unknown)
418
+ attrs.keys.should == [:id, :title, :content, :created_at, :author, :topics]
419
+ end
420
+
421
+ it "should let :include specify optional attribute groups" do
422
+ p = Post.first
423
+
424
+ attrs = p.api_attributes(:include => :extended_attrs)
425
+ attrs.keys.should == [:id, :title, :content, :created_at, :heavy_attr, :author, :topics]
426
+ end
427
+
428
+ it "should use :include option to retrieve optional associations" do
429
+ a = Author.first
430
+
431
+ attrs = a.api_attributes
432
+ attrs.should_not have_key(:posts)
433
+ attrs.should_not have_key(:author_group)
434
+
435
+ attrs = a.api_attributes(:include => :author_group)
436
+ attrs.should_not have_key(:posts)
437
+ attrs.should have_key(:author_group)
438
+
439
+ p = Post.first
440
+ attrs = p.api_attributes(:include => {:author => {:include => :posts}})
441
+ attrs[:author].should have_key(:posts)
442
+ attrs[:author][:posts].size.should == 3
443
+ end
444
+
445
+ it "should serialize a polymorphic one-one association" do
446
+ attrs = Author.find(5).api_attributes
447
+ attrs[:email][:special_email].should == 'special'
448
+ attrs[:email][:email].should == "author5@email.com"
449
+ end
450
+
451
+ it "should serialize a polymorphic collection" do
452
+ attrs = Post.first.api_attributes(:include => :comments)
453
+
454
+ attrs[:comments].should have(3).items
455
+ attrs[:comments][0].should_not have_key(:type)
456
+ attrs[:comments][1].should_not have_key(:type)
457
+ attrs[:comments].last[:type].should == 'Reply'
458
+ end
459
+
460
+ it "must allow including both optional attributes and associations with mixed arrays and hashes" do
461
+ p = Post.first
462
+ includes = {:include => [:extended_attrs, {:author => {:include => [:posts, :author_group]}}, :comments]}
463
+ attrs = p.api_attributes(includes)
464
+
465
+ attrs.keys.should == [:id, :title, :content, :created_at, :heavy_attr, :author, :topics, :comments]
466
+ attrs[:author].should have_key(:posts)
467
+ attrs[:author].should have_key(:author_group)
468
+ attrs[:comments].should have(3).items
469
+ end
470
+
471
+ it "should process includes specified in a hash" do
472
+ p = Post.first
473
+ includes = {:include => {:author => {:include => [:posts, :author_group]}, :comments => {}}}
474
+ attrs = p.api_attributes(includes)
475
+
476
+ attrs.keys.should == [:id, :title, :content, :created_at, :author, :topics, :comments]
477
+ attrs[:author].should have_key(:posts)
478
+ attrs[:author].should have_key(:author_group)
479
+ attrs[:comments].should have(3).items
480
+ end
481
+ end
482
+
483
+
484
+ describe "AttributeMap Deerializer" do
485
+ it "handles inputting attributes from a hash for new objects" do
486
+ h = {:title => "New title", :content => "New content"}
487
+
488
+ p = Post.new
489
+ p.api_attributes = h
490
+ p.attributes.should == {"id" => nil, "title"=>"New title", "content"=>"New content", "author_id"=>nil, "created_at"=>nil}
491
+ end
492
+
493
+ it "handles inputting attributes from a hash for existing objects" do
494
+ h = {:title => "New title", :content => "New content"}
495
+
496
+ p = Post.first
497
+ p.api_attributes = h
498
+ p.title.should == 'New title'
499
+ p.content.should == 'New content'
500
+ p.author_id.should_not be_nil
501
+ p.created_at.should_not be_nil
502
+ end
503
+
504
+ it "allows unrecognized and unspecified attributes but not set their values" do
505
+ h = {:title => "New title", :content => "New content", :author_id => 1, :unknown => 'sdfsdf'}
506
+
507
+ p = Post.new
508
+ p.api_attributes = h
509
+
510
+ p.attributes.should == {"id" => nil, "created_at"=>nil, "title"=>"New title", "content"=>"New content", "author_id"=>nil}
511
+ p[:unknown].should be_nil
512
+ end
513
+
514
+ it "does not overwrite read-only attributes" do
515
+ h = {:created_at => nil}
516
+
517
+ p = Post.first
518
+ p.api_attributes = h
519
+ p.changed?.should be_false
520
+ p.created_at.should_not be_nil
521
+ end
522
+
523
+ it "should let you specify an external name that is different from internal name" do
524
+ Post.map_attributes :test do
525
+ attribute :public_title, :model_attr => :title
526
+ end
527
+
528
+ p = Post.first
529
+ p.test_attributes = {:public_title => 'New title'}
530
+ p.title.should == 'New title'
531
+ end
532
+
533
+ it "should handle updating a one-to-one association attributes" do
534
+ h = {:author => {:id => 1, :first_name => 'New', :email => {:email => 'new_email'}}}
535
+
536
+ p = Post.first
537
+ p.api_attributes = h
538
+
539
+ p.author_id.should == 1
540
+ p.created_at.should_not be_nil
541
+ p.author.changed?.should be_true
542
+ p.author.first_name.should == 'New'
543
+ p.author.last_name.should == 'Smith'
544
+ p.author.email.email_addr.should == 'new_email'
545
+ end
546
+
547
+ it "must not overwrite read-only associations" do
548
+ Post.map_attributes :test do
549
+ association :author, :access => :ro
550
+ end
551
+ Author.map_attributes :test do
552
+ attribute :first_name
553
+ attribute :last_name
554
+ end
555
+
556
+ p = Post.first
557
+ p.test_attributes = {:author => {:first_name => 'New'}}
558
+ p.author.changed?.should be_false
559
+ p.author.first_name.should_not == 'New'
560
+ end
561
+
562
+ it "lets you specify an association external name that different that the internal name" do
563
+ Post.accepts_nested_attributes_for(:author, :update_only => true)
564
+ Post.map_attributes :test do
565
+ association :public_author, :using => :author
566
+ end
567
+ Author.map_attributes :test do
568
+ attribute :first_name
569
+ attribute :last_name
570
+ end
571
+
572
+ p = Post.first
573
+ p.test_attributes = {:public_author => {:first_name => 'New'}}
574
+
575
+ p.author_id.should == 1
576
+ p.author.changed?.should be_true
577
+ p.author.first_name.should == 'New'
578
+ end
579
+
580
+ it "sets STI base class attributes and associations when writing to subclass" do
581
+ r = Reply.new
582
+ r.api_attributes = {:content => 'Content for test', :post => {:title => 'STI Title'}}
583
+
584
+ r.content.should == 'Content for test'
585
+ r.post.id.should == nil
586
+ r.post.title.should == 'STI Title'
587
+ r.type.should == 'Reply'
588
+ end
589
+
590
+ it "should delete a one-one association item" do
591
+ h = {:email => {:id => 4, :_destroy => true}}
592
+
593
+ a = Author.find(4)
594
+ a.api_attributes = h
595
+
596
+ a.email.should be_marked_for_destruction
597
+ end
598
+
599
+ it "should add an item to a one-many association" do
600
+ h = {:comments => [{:commentor => 'A Commentor', :content => 'Some new comment'}]}
601
+
602
+ p = Post.first
603
+ p.api_attributes = h
604
+
605
+ p.comments.should have(4).items
606
+ p.comments.last.new_record?.should be_true
607
+ end
608
+
609
+ it "should update an item to a one-many association" do
610
+ h = {:comments => [{:id => 1, :commentor => 'A Commentor'}]}
611
+
612
+ p = Post.first
613
+ p.api_attributes = h
614
+
615
+ p.comments.should have(3).items
616
+ p.comments.first.new_record?.should be_false
617
+ p.comments.first.should be_changed
618
+ p.comments.first.commentor.should == 'A Commentor'
619
+ p.comments.first.content.should == 'Comment 1 for post 1'
620
+ end
621
+
622
+ it "should delete an item from a one-many association" do
623
+ h = {:comments => [{:id => 1, :_destroy => true}]}
624
+
625
+ p = Post.first
626
+ p.api_attributes = h
627
+
628
+ p.comments.should have(3).items
629
+ p.comments.first.should be_marked_for_destruction
630
+ end
631
+
632
+ it "should not allow delete if the association map spec doesn't allow it" do
633
+ Comment.map_attributes :test do
634
+ attribute :content
635
+ end
636
+ Post.has_many :comments_no_delete, :class_name => 'Comment'
637
+ Post.accepts_nested_attributes_for(:comments_no_delete, :allow_destroy => false)
638
+ Post.attr_accessible(:comments_no_delete_attributes)
639
+ Post.map_attributes :test do
640
+ attribute :title
641
+ association :comments_no_delete
642
+ end
643
+
644
+ h = {:comments => [{:id => 1, :_destroy => true}]}
645
+
646
+ p = Post.first
647
+ p.test_attributes = h
648
+
649
+ p.comments.should have(3).items
650
+ p.comments.first.should_not be_marked_for_destruction
651
+ end
652
+
653
+ it "should serialize a polymorphic collection" do
654
+ attrs = Post.first.api_attributes(:include => :comments)
655
+
656
+ attrs[:comments].should have(3).items
657
+ attrs[:comments][0].should_not have_key(:type)
658
+ attrs[:comments][1].should_not have_key(:type)
659
+ attrs[:comments].last[:type].should == 'Reply'
660
+ end
661
+
662
+ end