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.
- 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
|