jsonapi-resources 0.0.4 → 0.0.5
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.
- checksums.yaml +4 -4
- data/.travis.yml +4 -0
- data/README.md +186 -45
- data/lib/jsonapi/association.rb +6 -20
- data/lib/jsonapi/configuration.rb +27 -0
- data/lib/jsonapi/error_codes.rb +2 -0
- data/lib/jsonapi/exceptions.rb +41 -0
- data/lib/jsonapi/formatter.rb +94 -0
- data/lib/jsonapi/operation.rb +46 -9
- data/lib/jsonapi/request.rb +178 -48
- data/lib/jsonapi/resource.rb +51 -84
- data/lib/jsonapi/resource_controller.rb +53 -25
- data/lib/jsonapi/resource_for.rb +4 -6
- data/lib/jsonapi/resource_serializer.rb +59 -31
- data/lib/jsonapi/resources/version.rb +1 -1
- data/lib/jsonapi/routing_ext.rb +9 -1
- data/lib/jsonapi-resources.rb +2 -0
- data/test/controllers/controller_test.rb +706 -335
- data/test/fixtures/active_record.rb +60 -24
- data/test/integration/requests/request_test.rb +10 -15
- data/test/integration/routes/routes_test.rb +68 -20
- data/test/test_helper.rb +45 -3
- data/test/unit/operation/operations_processor_test.rb +49 -7
- data/test/unit/resource/resource_test.rb +2 -2
- data/test/unit/serializer/serializer_test.rb +483 -360
- metadata +5 -2
@@ -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 :
|
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 :
|
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
|
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 :
|
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
|
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
|
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
|
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.
|
344
|
-
super(
|
367
|
+
def self.updateable_fields(context)
|
368
|
+
super(context) - [:author, :subject]
|
345
369
|
end
|
346
370
|
|
347
|
-
def self.
|
348
|
-
super(
|
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
|
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
|
408
|
+
attributes :id, :cost
|
409
|
+
attribute :transaction_date, format: :date
|
387
410
|
|
388
|
-
has_one :
|
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
|
-
|
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
|
-
|
546
|
-
|
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:
|
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:
|
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',
|
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({
|
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({
|
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({
|
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({
|
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({
|
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({
|
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({
|
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({
|
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
|
38
|
-
assert_routing({
|
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({
|
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({
|
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({
|
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({
|
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({
|
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({
|
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({
|
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 },
|
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 },
|
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 },
|
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 :
|
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 :
|
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
|
-
|
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
|
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(:
|
75
|
-
|
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
|
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
|
-
|
87
|
-
|
88
|
-
|
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(
|
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
|