delineate 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/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