Single Table Inheritance (STI) on jsonapi-resources
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
Inherited configuration
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