-
Notifications
You must be signed in to change notification settings - Fork 7
Rails STI support in Ember Application Serializer
This page exists to provide historical context and motivation for the complex code in the Application Serializer on the client side.
Right after we switched over to Ember in like March of 2014, we realized that Ember Data didn't do STI out of the box (our senior engineer was flabbergasted). The Ember Data store deals with polymorphism in a different way than Rails does, especially with the way we use ActiveModelSerializers. The expectations of Ember's ActiveModelSerializers implementation are a bit at odds with how we (at least thought at the time) needed to serialize down type information for those Tasks.
It's useful to take a look at https://github.com/ember-data/active-model-adapter. The adapter takes the rails response as an input and spits out the JSON API document as its output, and then that JSON API document gets pushed into the store. In considering what needs to happen it's helpful mentally to split those two steps apart. Almost all of what we do in our custom code it working with/around the existing adapter's expectations to get a JSON API document that the store expects.
For historical
flavor, https://github.com/Bestra/ember-data-sti-guide is something I
wrote with Ember Data 1.8ish stuff in mind after we did our initial
implementation (if you google for "ember rails sti" it's sadly the #1
result). That document is outdated in terms of our current
implementation but it still reflects our motivation at the time. To
summarize the main nasty case: There are 2 places in the app
(the paper.task.index
route and the paper.task.version
route where
we say something like store.findRecord('task', 5) but we don't actually
know what type of task we're going to put in the store. Ember data
doesn't expect that, so we have to implement some work arounds.
There's an older RFC for adding polymorphic find support to the ember store, but it hasn't seen much activity: https://github.com/emberjs/rfcs/pull/67
Ember Data 2.0 changed the serializer api significantly. We made our existing implementation a little more general, but a little harder to follow code-wise. It deals with all our payloads in the same way rather than looking for tasks specifically.
Sideloading! We first tried just doing this munging in the Task Serializer, but the problem we ran into was that Tasks would be sideloaded in the payloads that were dealt with by other serializers, and those Tasks would fail to munge correctly. We moved the munging code into the Application Serializer to make sure it would happen no matter what.
The complexity of the implementation stems from its generality, as well as from the layer of the adapter/serializer chain in which we've implemented it. We very well might be able to remove our nastiest cases (meaning do some workarounds to avoid store.findRecord('task', 1). We might be able to shift some complexity to the Rails side, or in general change how we serialize down our Task payloads. I think our many Task model types on the ember side are here to stay for now, if only because we've attached different methods to the subclasses.