That was painful … Dealing with Ecto changesets.
The thing is, I’ve been trying to implement a way to use changesets in order to protect certain properties of the model from being modified by an external source. For example, users of the app can change their username, but not their rating.
To achieve something like that, I first created
external_changeset on the
Given the user, and the proposed parameters to be changed, we should return a changeset with the following conditions:
- The changes shouldn’t modify protected members
- The changes shouldn’t render the model in an invalid state (e.g. empty username)
Well, I thought it was simple at first, because I’ve seen the
cast method in action.
cast is a method on
Ecto.Changeset that allows you to control the changes in a certain way…
The thing is, I’ve always thought that the rules you pass into the
cast method are applied to the
Ecto.Changeset model itself, but no! The rules are actually applied to the final resulting model! What does that mean?
Well, first, let’s see what the
cast method does:
Depending on whether you are on the latest ecto release or not, cast takes the model or changeset as the first parameter, then the changes as a map, then an enumerable of fields that are required or can be modified.
That’s where my earlier statement comes into play. Notice how even though we “require” an email field, the changes map doesn’t have an email. That’s fine, because if the user object itself has the email set, that means the overall changeset is still valid!
Phew! I needed to write all that out, since I am sure my future self will need it.