Обновление местоположения cast_coordinate выдает ошибку аргумента

#elixir #phoenix-framework #ecto

Вопрос:

У меня есть locations таблица, в которой хранится пользователь latitude И. longitude Я использую Postgres/Postgis 13 его вместе с расширением для генерации координат. Ниже приведена моя модель:

   schema "locations" do
    field :latitude, :float
    field :longitude, :float
    field :context, :string
    field :publish, :boolean
    field :coordinates, Geo.PostGIS.Geometry
    belongs_to(:user, User)

    timestamps()
  end

  @doc false
  def changeset(location, attrs) do
    location
    |> cast(attrs, [:user_id, :context, :longitude, :latitude, :publish])
    |> validate_required([:user_id, :context, :longitude, :latitude])
    |> cast_coordinates()
  end

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

когда я create_location :

   def create_location(attrs \ %{}) do
    IO.inspect(attrs)
    %Location{}
    |> Location.changeset(attrs)
    |> Repo.insert()
  end
 

Все работает успешно. changeset В cast_coordinates том, что:

 cast coordinate
#Ecto.Changeset<
  action: nil,
  changes: %{
    context: "sss shop",
    latitude: 38.115556,
    longitude: 13.361389,
    profile_id: 5,
    publish: true,
    user_id: 2
  },
  errors: [],
  data: #OkBackend.Gis.ProfileLocation<>,
  valid?: true
>
 

Но когда я update_location :

   def update_location(%Location{} = location, attrs) do
    location
    |> Location.changeset(attrs)
    |> Repo.update()
  end
 

Как-то мой cast_coordinate бросок argument error , потому changeset что это:

 #Ecto.Changeset<action: nil, changes: %{}, errors: [],


 data: #OkBackend.Gis.ProfileLocation<>, valid?: true>
 

Как вы можете видеть, внутри ничего changes нет .

Это почему? И как я могу это решить?

Ответ №1:

Я думаю, это может быть связано с тем, что в вашей cast_coordinates функции вы используете get_change(changeset, :longitude) .

Это приведет change к longitude полю, но если вы не меняете поле, оно вернется nil .

Вместо этого вы должны использовать get_field(changeset, :longitude) , чтобы получить измененную долготу или существующую долготу, если она не изменилась, как это:

   @spec cast_coordinates(Ecto.Changeset.t()) :: Ecto.Changeset.t()
  def cast_coordinates(changeset) do
    lat = get_field(changeset, :latitude)
    lng = get_field(changeset, :longitude)
    geo = %Geo.Point{coordinates: {lng, lat}, srid: 4326}
    changeset |> put_change(:coordinates, geo)
  end