@@ -8,6 +8,11 @@ class BookResource < JsonapiCompliable::Resource
88 allow_filter :id
99 end
1010
11+ class DwellingResource < JsonapiCompliable ::Resource
12+ type :dwellings
13+ use_adapter JsonapiCompliable ::Adapters ::ActiveRecord
14+ end
15+
1116 class StateResource < JsonapiCompliable ::Resource
1217 type :states
1318 use_adapter JsonapiCompliable ::Adapters ::ActiveRecord
@@ -18,6 +23,12 @@ class BioResource < JsonapiCompliable::Resource
1823 use_adapter JsonapiCompliable ::Adapters ::ActiveRecord
1924 end
2025
26+ class HobbyResource < JsonapiCompliable ::Resource
27+ type :hobbies
28+ allow_filter :id
29+ use_adapter JsonapiCompliable ::Adapters ::ActiveRecord
30+ end
31+
2132 class AuthorResource < JsonapiCompliable ::Resource
2233 type :authors
2334 use_adapter JsonapiCompliable ::Adapters ::ActiveRecord
@@ -38,6 +49,26 @@ class AuthorResource < JsonapiCompliable::Resource
3849 foreign_key : :author_id ,
3950 scope : -> { Bio . all } ,
4051 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+ }
4172 end
4273 end
4374
@@ -49,15 +80,19 @@ def index
4980 end
5081 end
5182
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 ) }
5485 let! ( :book1 ) { Book . create! ( author : author1 , title : 'The Shining' ) }
5586 let! ( :book2 ) { Book . create! ( author : author1 , title : 'The Stand' ) }
5687 let! ( :state ) { State . create! ( name : 'Maine' ) }
5788 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' ) }
5893
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 }
6196 end
6297
6398 it 'allows basic sorting' do
@@ -84,17 +119,17 @@ def book_ids
84119 # TODO: may want to blow up here, only for index action
85120 it 'allows pagination of sideloaded resource' do
86121 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 ] )
88123 end
89124
90125 it 'allows sorting of sideloaded resource' do
91126 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 ] )
93128 end
94129
95130 it 'allows filtering of sideloaded resource' do
96131 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 ] )
98133 end
99134
100135 it 'allows extra fields for sideloaded resource' do
@@ -150,6 +185,66 @@ def book_ids
150185 end
151186 end
152187
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+
153248 context 'when overriding the resource' do
154249 before do
155250 controller . class_eval do
0 commit comments