jsonapi-resources 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -40,17 +40,20 @@ ActiveRecord::Schema.define do
40
40
  create_table :posts_tags, force: true do |t|
41
41
  t.references :post, :tag, index: true
42
42
  end
43
+ add_index :posts_tags, [:post_id, :tag_id], unique: true
43
44
 
44
45
  create_table :comments_tags, force: true do |t|
45
46
  t.references :comment, :tag, index: true
46
47
  end
47
48
 
48
- create_table :currencies, id: false, force: true do |t|
49
+ create_table :iso_currencies, id: false, force: true do |t|
49
50
  t.string :code, limit: 3, null: false
50
51
  t.string :name
52
+ t.string :country_name
53
+ t.string :minor_unit
51
54
  t.timestamps
52
55
  end
53
- add_index :currencies, :code, unique: true
56
+ add_index :iso_currencies, :code, unique: true
54
57
 
55
58
  create_table :expense_entries, force: true do |t|
56
59
  t.string :currency_code, limit: 3, null: false
@@ -65,6 +68,11 @@ ActiveRecord::Schema.define do
65
68
  t.integer :planet_type_id
66
69
  end
67
70
 
71
+ create_table :planets_tags, force: true do |t|
72
+ t.references :planet, :tag, index: true
73
+ end
74
+ add_index :planets_tags, [:planet_id, :tag_id], unique: true
75
+
68
76
  create_table :planet_types, force: true do |t|
69
77
  t.string :name
70
78
  end
@@ -109,24 +117,27 @@ end
109
117
 
110
118
  class Tag < ActiveRecord::Base
111
119
  has_and_belongs_to_many :posts, join_table: :posts_tags
120
+ has_and_belongs_to_many :planets, join_table: :planets_tags
112
121
  end
113
122
 
114
123
  class Section < ActiveRecord::Base
115
124
  end
116
125
 
117
- class Currency < ActiveRecord::Base
126
+ class IsoCurrency < ActiveRecord::Base
118
127
  self.primary_key = :code
119
- has_many :expense_entries, foreign_key: 'currency_code'
128
+ # has_many :expense_entries, foreign_key: 'currency_code'
120
129
  end
121
130
 
122
131
  class ExpenseEntry < ActiveRecord::Base
123
132
  belongs_to :employee, class_name: 'Person', foreign_key: 'employee_id'
124
- belongs_to :currency, class_name: 'Currency', foreign_key: 'currency_code'
133
+ belongs_to :iso_currency, foreign_key: 'currency_code'
125
134
  end
126
135
 
127
136
  class Planet < ActiveRecord::Base
128
137
  has_many :moons
129
138
  has_one :planet_type
139
+
140
+ has_and_belongs_to_many :tags, join_table: :planets_tags
130
141
  end
131
142
 
132
143
  class PlanetType < ActiveRecord::Base
@@ -204,7 +215,7 @@ end
204
215
  class TagsController < JSONAPI::ResourceController
205
216
  end
206
217
 
207
- class CurrenciesController < JSONAPI::ResourceController
218
+ class IsoCurrenciesController < JSONAPI::ResourceController
208
219
  end
209
220
 
210
221
  class ExpenseEntriesController < JSONAPI::ResourceController
@@ -228,7 +239,7 @@ module Api
228
239
  class TagsController < JSONAPI::ResourceController
229
240
  end
230
241
 
231
- class CurrenciesController < JSONAPI::ResourceController
242
+ class IsoCurrenciesController < JSONAPI::ResourceController
232
243
  end
233
244
 
234
245
  class ExpenseEntriesController < JSONAPI::ResourceController
@@ -236,6 +247,15 @@ module Api
236
247
 
237
248
  class BreedsController < JSONAPI::ResourceController
238
249
  end
250
+
251
+ class PlanetsController < JSONAPI::ResourceController
252
+ end
253
+
254
+ class PlanetTypesController < JSONAPI::ResourceController
255
+ end
256
+
257
+ class MoonsController < JSONAPI::ResourceController
258
+ end
239
259
  end
240
260
 
241
261
  module V2
@@ -260,7 +280,9 @@ end
260
280
 
261
281
  ### RESOURCES
262
282
  class PersonResource < JSONAPI::Resource
263
- attributes :id, :name, :email, :date_joined
283
+ attributes :id, :name, :email
284
+ attribute :date_joined, format: :date_with_timezone
285
+
264
286
  has_many :comments
265
287
  has_many :posts
266
288
 
@@ -317,6 +339,8 @@ class TagResource < JSONAPI::Resource
317
339
  attributes :id, :name
318
340
 
319
341
  has_many :posts
342
+ # Not including the planets association so they don't get output
343
+ #has_many :planets
320
344
  end
321
345
 
322
346
  class SectionResource < JSONAPI::Resource
@@ -340,12 +364,12 @@ class PostResource < JSONAPI::Resource
340
364
  filters :title, :author, :tags, :comments
341
365
  filter :id
342
366
 
343
- def self.updateable(keys, context = nil)
344
- super(keys - [:author, :subject])
367
+ def self.updateable_fields(context)
368
+ super(context) - [:author, :subject]
345
369
  end
346
370
 
347
- def self.createable(keys, context = nil)
348
- super(keys - [:subject])
371
+ def self.createable_fields(context)
372
+ super(context) - [:subject]
349
373
  end
350
374
 
351
375
  def self.verify_custom_filter(filter, values, context = nil)
@@ -373,24 +397,24 @@ class PostResource < JSONAPI::Resource
373
397
  end
374
398
  end
375
399
 
376
- class CurrencyResource < JSONAPI::Resource
400
+ class IsoCurrencyResource < JSONAPI::Resource
377
401
  key :code
378
- attributes :code, :name
402
+ attributes :code, :name, :country_name, :minor_unit
379
403
 
380
404
  routing_options :param => :code
381
-
382
- has_many :expense_entries
383
405
  end
384
406
 
385
407
  class ExpenseEntryResource < JSONAPI::Resource
386
- attributes :id, :cost, :transaction_date
408
+ attributes :id, :cost
409
+ attribute :transaction_date, format: :date
387
410
 
388
- has_one :currency, class_name: 'Currency', key: 'currency_code'
389
- has_one :employee
411
+ has_one :iso_currency, key: 'currency_code', primary_key: 'code'
412
+ has_one :employee, class_name: 'Person'
390
413
  end
391
414
 
392
415
  class BreedResource < JSONAPI::Resource
393
- attributes :id, :name
416
+ attribute :id, format_misspelled: :does_not_exist
417
+ attribute :name, format: :title
394
418
 
395
419
  def self.find(attrs, context = nil)
396
420
  breeds = []
@@ -412,6 +436,14 @@ class PlanetResource < JSONAPI::Resource
412
436
 
413
437
  has_many :moons
414
438
  has_one :planet_type
439
+
440
+ has_many :tags, acts_as_set: true
441
+ end
442
+
443
+ class PropertyResource < JSONAPI::Resource
444
+ attributes :id, :name
445
+
446
+ has_many :planets
415
447
  end
416
448
 
417
449
  class PlanetTypeResource < JSONAPI::Resource
@@ -542,25 +574,27 @@ Post.create(title: 'JR How To',
542
574
  post.tags.concat jr_tag
543
575
  end
544
576
 
545
- Currency.create(code: 'USD', name: 'United States Dollar')
546
- Currency.create(code: 'EUR', name: 'Euro Member Countries')
577
+ IsoCurrency.create(code: 'USD', name: 'United States Dollar', country_name: 'United States', minor_unit: 'cent')
578
+ IsoCurrency.create(code: 'EUR', name: 'Euro Member Countries', country_name: 'Euro Member Countries', minor_unit: 'cent')
547
579
 
548
580
  ExpenseEntry.create(currency_code: 'USD',
549
581
  employee_id: c.id,
550
582
  cost: '12.05',
551
- transaction_date: DateTime.parse('2014-04-15 12:13:14 UTC +00:00'))
583
+ transaction_date: Date.parse('2014-04-15'))
552
584
 
553
585
  ExpenseEntry.create(currency_code: 'USD',
554
586
  employee_id: c.id,
555
587
  cost: '12.06',
556
- transaction_date: DateTime.parse('2014-04-15 12:13:15 UTC +00:00'))
588
+ transaction_date: Date.parse('2014-04-15'))
557
589
 
590
+ # id:11
558
591
  Post.create(title: 'Tagged up post 1',
559
592
  body: 'AAAA',
560
593
  author_id: d.id,
561
594
  tag_ids: [6,7,8,9]
562
595
  )
563
596
 
597
+ # id:12
564
598
  Post.create(title: 'Tagged up post 2',
565
599
  body: 'BBBB',
566
600
  author_id: d.id,
@@ -583,3 +617,5 @@ jupiter = Planet.create(name: 'Jupiter', description: 'A gas giant.', planet_typ
583
617
  betax = Planet.create(name: 'Beta X', description: 'Newly discovered Planet X', planet_type_id: unknown.id)
584
618
  betay = Planet.create(name: 'Beta X', description: 'Newly discovered Planet Y', planet_type_id: unknown.id)
585
619
  betaz = Planet.create(name: 'Beta X', description: 'Newly discovered Planet Z', planet_type_id: unknown.id)
620
+ betaw = Planet.create(name: 'Beta W', description: 'Newly discovered Planet W')
621
+
@@ -9,23 +9,19 @@ class RequestTest < ActionDispatch::IntegrationTest
9
9
  end
10
10
 
11
11
  def test_put_single
12
- put '/posts/3', {"posts" => {"id" => "3", "title" => "A great new Post", "links" => { "tags" => [3,4] }}}
12
+ put '/posts/3',
13
+ {
14
+ 'posts' => {
15
+ 'id' => '3',
16
+ 'title' => 'A great new Post',
17
+ 'links' => {
18
+ 'tags' => [3, 4]
19
+ }
20
+ }
21
+ }
13
22
  assert_equal 200, status
14
23
  end
15
24
 
16
- # def test_put_links
17
- # put '/posts/3/links/tags', {"tags" => [1,4] }
18
- # assert_equal 200, status
19
- # end
20
-
21
- # def test_patch_create
22
- # patch '/posts',
23
- # {"op" => "add",
24
- # "path" => "/-",
25
- # "value" => {"title" => "Another great new Post", "body" => "saasd", "links" => { "author" => 3 }}}
26
- # assert_equal 200, status
27
- # end
28
-
29
25
  def test_destroy_single
30
26
  delete '/posts/7'
31
27
  assert_equal 204, status
@@ -36,4 +32,3 @@ class RequestTest < ActionDispatch::IntegrationTest
36
32
  assert_equal 204, status
37
33
  end
38
34
  end
39
-
@@ -3,83 +3,131 @@ require File.expand_path('../../../test_helper', __FILE__)
3
3
  class RoutesTest < ActionDispatch::IntegrationTest
4
4
 
5
5
  def test_routing_post
6
- assert_routing({ path: 'posts', method: :post }, { controller: 'posts', action: 'create' })
6
+ assert_routing({path: 'posts', method: :post},
7
+ {controller: 'posts', action: 'create'})
7
8
  end
8
9
 
9
10
  def test_routing_put
10
- assert_routing({ path: '/posts/1', method: :put }, { controller: 'posts', action: 'update', id: '1' })
11
+ assert_routing({path: '/posts/1', method: :put},
12
+ {controller: 'posts', action: 'update', id: '1'})
11
13
  end
12
14
 
13
15
  def test_routing_posts_show
14
- assert_routing({ path: '/posts/1', method: :get }, {action: 'show', controller: 'posts', id: '1'})
16
+ assert_routing({path: '/posts/1', method: :get},
17
+ {action: 'show', controller: 'posts', id: '1'})
15
18
  end
16
19
 
17
20
  def test_routing_posts_links_author_show
18
- assert_routing({ path: '/posts/1/links/author', method: :get }, { controller: 'posts', action: 'show_association', post_id: '1', association: 'author' })
21
+ assert_routing({path: '/posts/1/links/author', method: :get},
22
+ {controller: 'posts', action: 'show_association', post_id: '1', association: 'author'})
19
23
  end
20
24
 
21
25
  def test_routing_posts_links_author_destroy
22
- assert_routing({ path: '/posts/1/links/author', method: :delete }, { controller: 'posts', action: 'destroy_association', post_id: '1', association: 'author' })
26
+ assert_routing({path: '/posts/1/links/author', method: :delete},
27
+ {controller: 'posts', action: 'destroy_association', post_id: '1', association: 'author'})
23
28
  end
24
29
 
25
30
  def test_routing_posts_links_author_create
26
- assert_routing({ path: '/posts/1/links/author', method: :post }, { controller: 'posts', action: 'create_association', post_id: '1', association: 'author' })
31
+ assert_routing({path: '/posts/1/links/author', method: :post},
32
+ {controller: 'posts', action: 'create_association', post_id: '1', association: 'author'})
33
+ end
34
+
35
+ def test_routing_posts_links_author_update
36
+ assert_routing({path: '/posts/1/links/author', method: :put},
37
+ {controller: 'posts', action: 'update_association', post_id: '1', association: 'author'})
27
38
  end
28
39
 
29
40
  def test_routing_posts_links_tags_show
30
- assert_routing({ path: '/posts/1/links/tags', method: :get }, { controller: 'posts', action: 'show_association', post_id: '1', association: 'tags' })
41
+ assert_routing({path: '/posts/1/links/tags', method: :get},
42
+ {controller: 'posts', action: 'show_association', post_id: '1', association: 'tags'})
31
43
  end
32
44
 
33
45
  def test_routing_posts_links_tags_destroy
34
- assert_routing({ path: '/posts/1/links/tags/1,2', method: :delete }, { controller: 'posts', action: 'destroy_association', post_id: '1', keys: '1,2', association: 'tags' })
46
+ assert_routing({path: '/posts/1/links/tags/1,2', method: :delete},
47
+ {controller: 'posts', action: 'destroy_association', post_id: '1', keys: '1,2', association: 'tags'})
48
+ end
49
+
50
+ def test_routing_posts_links_tags_create
51
+ assert_routing({path: '/posts/1/links/tags', method: :post},
52
+ {controller: 'posts', action: 'create_association', post_id: '1', association: 'tags'})
53
+ end
54
+
55
+ def test_routing_posts_links_tags_update_acts_as_set
56
+ assert_routing({path: '/posts/1/links/tags', method: :put},
57
+ {controller: 'posts', action: 'update_association', post_id: '1', association: 'tags'})
35
58
  end
36
59
 
37
- def test_routing_posts_links_tags_update
38
- assert_routing({ path: '/posts/1/links/tags', method: :post }, { controller: 'posts', action: 'create_association', post_id: '1', association: 'tags' })
60
+ def test_routing_authors_show
61
+ assert_routing({path: '/authors/1', method: :get},
62
+ {action: 'show', controller: 'authors', id: '1'})
39
63
  end
40
64
 
65
+ def test_routing_author_links_posts_create_not_acts_as_set
66
+ assert_routing({path: '/authors/1/links/posts', method: :post},
67
+ {controller: 'authors', action: 'create_association', author_id: '1', association: 'posts'})
68
+ end
69
+
70
+ # ToDo: Test that non acts as set has_many association update route is not created
71
+ # def test_routing_author_links_posts_update_not_acts_as_set
72
+ # refute_routing({ path: '/authors/1/links/posts', method: :put },
73
+ # { controller: 'authors', action: 'update_association', author_id: '1', association: 'posts' })
74
+ # end
75
+
41
76
  # V1
42
77
  def test_routing_v1_posts_show
43
- assert_routing({ path: '/api/v1/posts/1', method: :get }, {action: 'show', controller: 'api/v1/posts', id: '1'})
78
+ assert_routing({path: '/api/v1/posts/1', method: :get},
79
+ {action: 'show', controller: 'api/v1/posts', id: '1'})
44
80
  end
45
81
 
46
82
  def test_routing_v1_posts_delete
47
- assert_routing({ path: '/api/v1/posts/1', method: :delete }, {action: 'destroy', controller: 'api/v1/posts', id: '1'})
83
+ assert_routing({path: '/api/v1/posts/1', method: :delete},
84
+ {action: 'destroy', controller: 'api/v1/posts', id: '1'})
48
85
  end
49
86
 
50
87
  def test_routing_v1_posts_links_author_show
51
- assert_routing({ path: '/api/v1/posts/1/links/author', method: :get }, { controller: 'api/v1/posts', action: 'show_association', post_id: '1', association: 'author' })
88
+ assert_routing({path: '/api/v1/posts/1/links/author', method: :get},
89
+ {controller: 'api/v1/posts', action: 'show_association', post_id: '1', association: 'author'})
52
90
  end
53
91
 
54
92
  # V2
55
93
  def test_routing_v2_posts_show
56
- assert_routing({ path: '/api/v2/authors/1', method: :get }, {action: 'show', controller: 'api/v2/authors', id: '1'})
94
+ assert_routing({path: '/api/v2/authors/1', method: :get},
95
+ {action: 'show', controller: 'api/v2/authors', id: '1'})
57
96
  end
58
97
 
59
98
  def test_routing_v2_posts_links_author_show
60
- assert_routing({ path: '/api/v2/posts/1/links/author', method: :get }, { controller: 'api/v2/posts', action: 'show_association', post_id: '1', association: 'author' })
99
+ assert_routing({path: '/api/v2/posts/1/links/author', method: :get},
100
+ {controller: 'api/v2/posts', action: 'show_association', post_id: '1', association: 'author'})
61
101
  end
62
102
 
63
103
  def test_routing_v2_preferences_show
64
- assert_routing({ path: '/api/v2/preferences', method: :get }, {action: 'show', controller: 'api/v2/preferences'})
104
+ assert_routing({path: '/api/v2/preferences', method: :get},
105
+ {action: 'show', controller: 'api/v2/preferences'})
65
106
  end
66
107
 
67
108
  # V3
68
109
  def test_routing_v3_posts_show
69
- assert_routing({ path: '/api/v3/posts/1', method: :get }, {action: 'show', controller: 'api/v3/posts', id: '1'})
110
+ assert_routing({path: '/api/v3/posts/1', method: :get},
111
+ {action: 'show', controller: 'api/v3/posts', id: '1'})
70
112
  end
71
113
 
72
114
  # ToDo: Refute routing
73
115
  # def test_routing_v3_posts_delete
74
- # assert_routing({ path: '/api/v3/posts/1', method: :delete }, {action: 'destroy', controller: 'api/v3/posts', id: '1'})
116
+ # assert_routing({ path: '/api/v3/posts/1', method: :delete },
117
+ # {action: 'destroy', controller: 'api/v3/posts', id: '1'})
75
118
  # end
76
119
 
77
120
  # def test_routing_posts_links_author_except_destroy
78
- # assert_routing({ path: '/api/v3/posts/1/links/author', method: :delete }, { controller: 'api/v3/posts', action: 'destroy_association', post_id: '1', association: 'author' })
121
+ # assert_routing({ path: '/api/v3/posts/1/links/author', method: :delete },
122
+ # { controller: 'api/v3/posts', action: 'destroy_association', post_id: '1', association: 'author' })
79
123
  # end
80
124
  #
81
125
  # def test_routing_posts_links_tags_only_create_show
82
- # assert_routing({ path: '/api/v3/posts/1/links/tags/1,2', method: :delete }, { controller: 'api/v3/posts', action: 'destroy_association', post_id: '1', keys: '1,2', association: 'tags' })
126
+ # assert_routing({ path: '/api/v3/posts/1/links/tags/1,2', method: :delete },
127
+ # { controller: 'api/v3/posts', action: 'destroy_association', post_id: '1', keys: '1,2', association: 'tags' })
83
128
  # end
129
+
130
+ # Test that non acts as set has_many association update route is not created
131
+
84
132
  end
85
133
 
data/test/test_helper.rb CHANGED
@@ -12,6 +12,8 @@ require 'minitest/spec'
12
12
  require 'rails/all'
13
13
 
14
14
  require 'jsonapi/routing_ext'
15
+ require 'jsonapi/configuration'
16
+ require 'jsonapi/formatter'
15
17
 
16
18
  require File.expand_path('../helpers/value_matchers', __FILE__)
17
19
  require File.expand_path('../helpers/hash_helpers', __FILE__)
@@ -19,6 +21,10 @@ require File.expand_path('../helpers/functional_helpers', __FILE__)
19
21
 
20
22
  Rails.env = 'test'
21
23
 
24
+ JSONAPI.configure do |config|
25
+ config.json_key_format = :camelized_key
26
+ end
27
+
22
28
  class TestApp < Rails::Application
23
29
  config.eager_load = false
24
30
  config.root = File.dirname(__FILE__)
@@ -40,7 +46,7 @@ TestApp.routes.draw do
40
46
  jsonapi_resources :tags
41
47
  jsonapi_resources :posts
42
48
  jsonapi_resources :sections
43
- jsonapi_resources :currencies
49
+ jsonapi_resources :iso_currencies
44
50
  jsonapi_resources :expense_entries
45
51
  jsonapi_resources :breeds
46
52
  jsonapi_resources :planets
@@ -57,7 +63,7 @@ TestApp.routes.draw do
57
63
  jsonapi_resources :tags
58
64
  jsonapi_resources :posts
59
65
  jsonapi_resources :sections
60
- jsonapi_resources :currencies
66
+ jsonapi_resources :iso_currencies
61
67
  jsonapi_resources :expense_entries
62
68
  jsonapi_resources :breeds
63
69
  jsonapi_resources :planets
@@ -74,7 +80,7 @@ TestApp.routes.draw do
74
80
 
75
81
  namespace :v3 do
76
82
  jsonapi_resource :preferences do
77
- # Intentionally empty block to skip association urls
83
+ # Intentionally empty block to skip association urls
78
84
  end
79
85
 
80
86
  jsonapi_resources :posts, except: [:destroy] do
@@ -96,3 +102,39 @@ class ActiveSupport::TestCase
96
102
  @routes = TestApp.routes
97
103
  end
98
104
  end
105
+
106
+ class UpperCamelizedKeyFormatter < JSONAPI::KeyFormatter
107
+ class << self
108
+ def format(key)
109
+ super.camelize(:upper)
110
+ end
111
+ end
112
+ end
113
+
114
+ class DateWithTimezoneValueFormatter < JSONAPI::ValueFormatter
115
+ class << self
116
+ def format(raw_value, source, context)
117
+ raw_value.in_time_zone('Eastern Time (US & Canada)').to_s
118
+ end
119
+ end
120
+ end
121
+
122
+ class DateValueFormatter < JSONAPI::ValueFormatter
123
+ class << self
124
+ def format(raw_value, source, context)
125
+ raw_value.strftime('%m/%d/%Y')
126
+ end
127
+ end
128
+ end
129
+
130
+ class TitleValueFormatter < JSONAPI::ValueFormatter
131
+ class << self
132
+ def format(raw_value, source, context)
133
+ super(raw_value, source, context).titlecase
134
+ end
135
+
136
+ def unformat(value, resource_klass, context)
137
+ value.to_s.downcase
138
+ end
139
+ end
140
+ end
@@ -7,6 +7,10 @@ require 'jsonapi/operations_processor'
7
7
 
8
8
  class OperationsProcessorTest < MiniTest::Unit::TestCase
9
9
  def setup
10
+ betax = Planet.find(5)
11
+ betay = Planet.find(6)
12
+ betaz = Planet.find(7)
13
+ unknown = PlanetType.find(5)
10
14
  end
11
15
 
12
16
  def test_create_single_resource
@@ -51,7 +55,7 @@ class OperationsProcessorTest < MiniTest::Unit::TestCase
51
55
  assert_equal(Planet.count, count + 3)
52
56
  end
53
57
 
54
- def test_add_has_one_association
58
+ def test_replace_has_one_association
55
59
  op = JSONAPI::OperationsProcessor.new()
56
60
 
57
61
  saturn = Planet.find(1)
@@ -71,11 +75,13 @@ class OperationsProcessorTest < MiniTest::Unit::TestCase
71
75
 
72
76
  assert_kind_of(Array, results)
73
77
  assert_kind_of(JSONAPI::OperationResult, results[0])
74
- assert_equal(:created, results[0].code)
75
- assert_equal(results[0].resource.object.attributes['planet_type_id'], gas_giant.id)
78
+ assert_equal(:no_content, results[0].code)
79
+
80
+ saturn.reload
81
+ assert_equal(saturn.planet_type_id, gas_giant.id)
76
82
  end
77
83
 
78
- def test_add_has_many_association
84
+ def test_create_has_many_association
79
85
  op = JSONAPI::OperationsProcessor.new()
80
86
 
81
87
  betax = Planet.find(5)
@@ -83,9 +89,12 @@ class OperationsProcessorTest < MiniTest::Unit::TestCase
83
89
  betaz = Planet.find(7)
84
90
  gas_giant = PlanetType.find(1)
85
91
  unknown = PlanetType.find(5)
86
- assert_equal(betax.planet_type_id, unknown.id)
87
- assert_equal(betay.planet_type_id, unknown.id)
88
- assert_equal(betaz.planet_type_id, unknown.id)
92
+ betax.planet_type_id = unknown.id
93
+ betay.planet_type_id = unknown.id
94
+ betaz.planet_type_id = unknown.id
95
+ betax.save!
96
+ betay.save!
97
+ betaz.save!
89
98
 
90
99
  operations = [
91
100
  JSONAPI::CreateHasManyAssociationOperation.new(PlanetTypeResource, gas_giant.id, :planets, [betax.id, betay.id, betaz.id])
@@ -105,6 +114,39 @@ class OperationsProcessorTest < MiniTest::Unit::TestCase
105
114
  assert_equal(betaz.planet_type_id, gas_giant.id)
106
115
  end
107
116
 
117
+ def test_replace_has_many_association
118
+ op = JSONAPI::OperationsProcessor.new()
119
+
120
+ betax = Planet.find(5)
121
+ betay = Planet.find(6)
122
+ betaz = Planet.find(7)
123
+ gas_giant = PlanetType.find(1)
124
+ unknown = PlanetType.find(5)
125
+ betax.planet_type_id = unknown.id
126
+ betay.planet_type_id = unknown.id
127
+ betaz.planet_type_id = unknown.id
128
+ betax.save!
129
+ betay.save!
130
+ betaz.save!
131
+
132
+ operations = [
133
+ JSONAPI::ReplaceHasManyAssociationOperation.new(PlanetTypeResource, gas_giant.id, :planets, [betax.id, betay.id, betaz.id])
134
+ ]
135
+
136
+ request = JSONAPI::Request.new
137
+ request.operations = operations
138
+
139
+ results = op.process(request)
140
+
141
+ betax.reload
142
+ betay.reload
143
+ betaz.reload
144
+
145
+ assert_equal(betax.planet_type_id, gas_giant.id)
146
+ assert_equal(betay.planet_type_id, gas_giant.id)
147
+ assert_equal(betaz.planet_type_id, gas_giant.id)
148
+ end
149
+
108
150
  def test_replace_attributes
109
151
  op = JSONAPI::OperationsProcessor.new()
110
152
 
@@ -33,8 +33,8 @@ class ResourceTest < MiniTest::Unit::TestCase
33
33
 
34
34
  def test_class_attributes
35
35
  attrs = CatResource._attributes
36
- assert_kind_of(Set, attrs)
37
- assert_equal(attrs.size, 3)
36
+ assert_kind_of(Hash, attrs)
37
+ assert_equal(attrs.keys.size, 3)
38
38
  end
39
39
 
40
40
  def test_class_assosications