Search code examples
elixirphoenix-frameworkecto

elixir ecto - changeset differences between create and update


I have this Ecto.Schema with the changeset like below:

  def changeset(current_case, attrs) do
    current_case
    |> cast(attrs, [:case_id, :latitude, :longitude, :user_id])
    |> cast_coordinates() 
    end

    def cast_coordinates(changeset) do
    lat = get_change(changeset, :latitude)
    lng = get_change(changeset, :longitude)
    geo = %Geo.Point{coordinates: {lng, lat}, srid: 4326}
    changeset |> put_change(:coordinates, geo)
    end

Basically, it is a simple table taking in case_id, latitude, longitude, user_id.

Occassionally, user will update their location but sometimes, they only update the case_id without update location.

cast_coordinates will take latitude and longitude to convert it into geo point then input into changeset.

when create/1, I won't have issue, because changes in changeset will have all the data.

but when update/2, I will get argument error if I only want to update:

  1. latitude only, because longitude in changes will be nil.
  2. longitude only, because latitude in changes will be nil.
  3. no location update, because both of it will be nil.
  4. I can't even forcefully inject latitude or longitude from current_case, changeset will treat them as no changes, thus the value will be nil.

How can I resolve this?


Solution

  • Use get_field/3 instead of get_change/3.

    get_change/3 only fetches changes, so if attrs doesn't include latitude or longitude, it will return nil.

    get_field/3 fetches from the changes or from the data. When updating, your data from current_case should contain the current latitude and longitude values, which will be returned instead of nil.