A critical model of ours utilizes STI, an incredibly useful tool in the right circumstances. Rails supports this gracefully; however, the JSONAPI Resources gem which implements our API required some hair-pulling.
Create routes, resources, and controllers for each subclass
You might try to define a JSONAPI classes for the parent only. While this may partially work, we found it best to define them for each STI subclass. This strategy allows for clean OOP-style behavior adjustments via overriding rather than a conditional. Plus, the large set of attributes required to create each type will likely vary.
As a result, you'll have these routes:
POST /fruit POST /apples POST /bananas
You'll have these resources:
# Parent class Api::V1::FruitResource < JSONAPI::Resource; end # STI Subclasses class Api::V1::AppleResource < Api::V1::FruitResource; end class Api::V1::BananaResource < Api::V1::FruitResource; end
You'll have these controllers:
# Parent class Api::V1::FruitController < JSONAPI::ResourceController; end # STI Subclasses class Api::V1::ApplesController < Api::V1::FruitController; end class Api::V1::BananasController < Api::V1::FruitController; end
Using the correct subclass in Resources
The main gotcha we encountered is that JR does not correctly determine the subclass model names. Unfortunately, you'll need to explicitly define them. You'd think this would work:
class Api::V1::AppleResource < Api::V1::FruitResource model_name 'Apple' end
It does not. Instead, directly override the class method:
class Api::V1::AppleResource < Api::V1::FruitResource def self._model_class Apple end end
JR does not inherit configuration. For example, if you are using a custom
primary_key for your whole Fruit model, each subclass needs to define it.
class Api::V1::FruitResource < JSONAPI::Resource primary_key :alphanumeric_id end class Api::V1::AppleResource < Api::V1::FruitResource primary_key :alphanumeric_id end