#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