Tutorial
Step 6: Customizing Writes
When we ran the generators (and created a blank Resource class), we got the ability to create, update, and destroy resources for free. You can turn off this behavior with self.read_only = true
. Or for relationships: has_many :positions, writable: false
.
But in RESTful APIs, it’s super common for persistence operations to have side effects - that’s how we avoid extraneous verbs and inconsistent patterns.
In a prior step, we updated position
Factory to automatically reorder
the historical_index
: when a new record comes in, all the prior
values need to change. This step will show how to add that behavior to
our API, using hooks that work for a variety of scenarios: sending
emails, checking authorization roles, queuing delayed jobs, and more.
The Rails Stuff 🚂
Previously, we put the logic that re-ordered the historical_index
column in the position
factory. Let’s move that to the model so our
tests and API can share the same logic:
The Graphiti Stuff 🎨
All Graphiti updates happen within a transaction. We want to insert our
code right before that transaction closes - after the graph of objects
has been persisted and validations have passed. To do that, we’ll use
the before_commit
hook:
Again, note that the Position.reorder!
code existed independent of our
API, and was re-used in our factory.
Digging Deeper 🧐
Resources come with Lifecycle Hooks, similar to ActiveRecord Callbacks.
Those callbacks have gotten a bad reputation. This is because your Model can be - is supposed to be - used in a variety of contexts across your application. Some of those contexts will want a given callback to fire, others will not, and accomodating the conditionals gets hairy. This is why many developers move that functionality into Service Objects.
But Resource callbacks don’t have the same problem - they only fire in the context of your API, and can be associated to a single endpoint. You can still use Service Objects if you’d like; Graphiti callbacks simply wire them up.