@@ -8,6 +8,11 @@ class BookResource < JsonapiCompliable::Resource
8
8
allow_filter :id
9
9
end
10
10
11
+ class DwellingResource < JsonapiCompliable ::Resource
12
+ type :dwellings
13
+ use_adapter JsonapiCompliable ::Adapters ::ActiveRecord
14
+ end
15
+
11
16
class StateResource < JsonapiCompliable ::Resource
12
17
type :states
13
18
use_adapter JsonapiCompliable ::Adapters ::ActiveRecord
@@ -18,6 +23,12 @@ class BioResource < JsonapiCompliable::Resource
18
23
use_adapter JsonapiCompliable ::Adapters ::ActiveRecord
19
24
end
20
25
26
+ class HobbyResource < JsonapiCompliable ::Resource
27
+ type :hobbies
28
+ allow_filter :id
29
+ use_adapter JsonapiCompliable ::Adapters ::ActiveRecord
30
+ end
31
+
21
32
class AuthorResource < JsonapiCompliable ::Resource
22
33
type :authors
23
34
use_adapter JsonapiCompliable ::Adapters ::ActiveRecord
@@ -38,6 +49,26 @@ class AuthorResource < JsonapiCompliable::Resource
38
49
foreign_key : :author_id ,
39
50
scope : -> { Bio . all } ,
40
51
resource : BioResource
52
+
53
+ has_and_belongs_to_many :hobbies ,
54
+ resource : HobbyResource ,
55
+ scope : -> { Hobby . all } ,
56
+ foreign_key : { author_hobbies : :author_id }
57
+
58
+ polymorphic_belongs_to :dwelling ,
59
+ group_by : proc { |author | author . dwelling_type } ,
60
+ groups : {
61
+ 'House' => {
62
+ foreign_key : :dwelling_id ,
63
+ resource : DwellingResource ,
64
+ scope : -> { House . all }
65
+ } ,
66
+ 'Condo' => {
67
+ foreign_key : :dwelling_id ,
68
+ resource : DwellingResource ,
69
+ scope : -> { Condo . all }
70
+ }
71
+ }
41
72
end
42
73
end
43
74
@@ -49,15 +80,19 @@ def index
49
80
end
50
81
end
51
82
52
- let! ( :author1 ) { Author . create! ( first_name : 'Stephen' , state : state ) }
53
- let! ( :author2 ) { Author . create! ( first_name : 'George' ) }
83
+ let! ( :author1 ) { Author . create! ( first_name : 'Stephen' , dwelling : house , state : state ) }
84
+ let! ( :author2 ) { Author . create! ( first_name : 'George' , dwelling : condo ) }
54
85
let! ( :book1 ) { Book . create! ( author : author1 , title : 'The Shining' ) }
55
86
let! ( :book2 ) { Book . create! ( author : author1 , title : 'The Stand' ) }
56
87
let! ( :state ) { State . create! ( name : 'Maine' ) }
57
88
let! ( :bio ) { Bio . create! ( author : author1 , picture : 'imgur' , description : 'author bio' ) }
89
+ let! ( :hobby1 ) { Hobby . create! ( name : 'Fishing' , authors : [ author1 ] ) }
90
+ let! ( :hobby2 ) { Hobby . create! ( name : 'Woodworking' , authors : [ author1 ] ) }
91
+ let ( :house ) { House . new ( name : 'Cozy' ) }
92
+ let ( :condo ) { Condo . new ( name : 'Modern' ) }
58
93
59
- def book_ids
60
- json_includes ( 'books' ) . map { |b | b [ 'id' ] . to_i }
94
+ def ids_for ( type )
95
+ json_includes ( type ) . map { |b | b [ 'id' ] . to_i }
61
96
end
62
97
63
98
it 'allows basic sorting' do
@@ -84,17 +119,17 @@ def book_ids
84
119
# TODO: may want to blow up here, only for index action
85
120
it 'allows pagination of sideloaded resource' do
86
121
get :index , params : { include : 'books' , page : { books : { size : 1 , number : 2 } } }
87
- expect ( book_ids ) . to eq ( [ book2 . id ] )
122
+ expect ( ids_for ( 'books' ) ) . to eq ( [ book2 . id ] )
88
123
end
89
124
90
125
it 'allows sorting of sideloaded resource' do
91
126
get :index , params : { include : 'books' , sort : '-books.title' }
92
- expect ( book_ids ) . to eq ( [ book2 . id , book1 . id ] )
127
+ expect ( ids_for ( 'books' ) ) . to eq ( [ book2 . id , book1 . id ] )
93
128
end
94
129
95
130
it 'allows filtering of sideloaded resource' do
96
131
get :index , params : { include : 'books' , filter : { books : { id : book2 . id } } }
97
- expect ( book_ids ) . to eq ( [ book2 . id ] )
132
+ expect ( ids_for ( 'books' ) ) . to eq ( [ book2 . id ] )
98
133
end
99
134
100
135
it 'allows extra fields for sideloaded resource' do
@@ -150,6 +185,66 @@ def book_ids
150
185
end
151
186
end
152
187
188
+ context 'sideloading has_and_belongs_to_many' do
189
+ it 'allows sorting of sideloaded resource' do
190
+ get :index , params : { include : 'hobbies' , sort : '-hobbies.name' }
191
+ expect ( ids_for ( 'hobbies' ) ) . to eq ( [ hobby2 . id , hobby1 . id ] )
192
+ end
193
+
194
+ it 'allows filtering of sideloaded resource' do
195
+ get :index , params : { include : 'hobbies' , filter : { hobbies : { id : hobby2 . id } } }
196
+ expect ( ids_for ( 'hobbies' ) ) . to eq ( [ hobby2 . id ] )
197
+ end
198
+
199
+ it 'allows extra fields for sideloaded resource' do
200
+ get :index , params : { include : 'hobbies' , extra_fields : { hobbies : 'reason' } }
201
+ hobby = json_includes ( 'hobbies' ) [ 0 ]
202
+ expect ( hobby [ 'name' ] ) . to be_present
203
+ expect ( hobby [ 'description' ] ) . to be_present
204
+ expect ( hobby [ 'reason' ] ) . to eq ( 'hobby reason' )
205
+ end
206
+
207
+ it 'allows sparse fieldsets for the sideloaded resource' do
208
+ get :index , params : { include : 'hobbies' , fields : { hobbies : 'name' } }
209
+ hobby = json_includes ( 'hobbies' ) [ 0 ]
210
+ expect ( hobby [ 'name' ] ) . to be_present
211
+ expect ( hobby ) . to_not have_key ( 'description' )
212
+ expect ( hobby ) . to_not have_key ( 'reason' )
213
+ end
214
+ end
215
+
216
+ context 'sideloading polymorphic belongs_to' do
217
+ it 'allows extra fields for the sideloaded resource' do
218
+ get :index , params : {
219
+ include : 'dwelling' ,
220
+ extra_fields : { houses : 'house_price' , condos : 'condo_price' }
221
+ }
222
+ house = json_includes ( 'houses' ) [ 0 ]
223
+ expect ( house [ 'name' ] ) . to be_present
224
+ expect ( house [ 'house_description' ] ) . to be_present
225
+ expect ( house [ 'house_price' ] ) . to eq ( 1_000_000 )
226
+ condo = json_includes ( 'condos' ) [ 0 ]
227
+ expect ( condo [ 'name' ] ) . to be_present
228
+ expect ( condo [ 'condo_description' ] ) . to be_present
229
+ expect ( condo [ 'condo_price' ] ) . to eq ( 500_000 )
230
+ end
231
+
232
+ it 'allows sparse fieldsets for the sideloaded resource' do
233
+ get :index , params : {
234
+ include : 'dwelling' ,
235
+ fields : { houses : 'name' , condos : 'condo_description' }
236
+ }
237
+ house = json_includes ( 'houses' ) [ 0 ]
238
+ expect ( house [ 'name' ] ) . to be_present
239
+ expect ( house ) . to_not have_key ( 'house_description' )
240
+ expect ( house ) . to_not have_key ( 'house_price' )
241
+ condo = json_includes ( 'condos' ) [ 0 ]
242
+ expect ( condo [ 'condo_description' ] ) . to be_present
243
+ expect ( condo ) . to_not have_key ( 'name' )
244
+ expect ( condo ) . to_not have_key ( 'condo_price' )
245
+ end
246
+ end
247
+
153
248
context 'when overriding the resource' do
154
249
before do
155
250
controller . class_eval do
0 commit comments