How to use Geo library to create valid Ecto Model changeset?
Asked Answered
S

2

8

I'm trying to use Geo library to store Geo.Point via Phoenix model changeset. My params are: {coordinates: [49.44, 17.87]} or more prefer would be {coordinates: {latitude: 49.44, longitude: 17.87}}

In iex console I tried:

iex(5)> changeset = Place.changeset(%Place{}, %{coordinates: [49.44, 17.87]})
%Ecto.Changeset{action: nil, changes: %{}, constraints: [],
 errors: [coordinates: "is invalid"], filters: %{}
 model: %Myapp.Place{__meta__: #Ecto.Schema.Metadata<:built>,
  coordinates: nil, id: nil, inserted_at: nil, updated_at: nil}, optional: [],
 opts: [], params: %{"coordinates" => [49.445614899999995, 17.875574099999998]},
 repo: nil, required: [:coordinates],

All other attempts ended by Poison.Parser errors.

How should looks params from client side to create valid changeset?

Model:

defmodule MyApp.Place do
  use MyApp.Web, :model

  schema "place" do
    field :coordinates, Geo.Point

    timestamps
  end

  @required_fields ~w(coordinates)
  @optional_fields ~w()

  def changeset(model, params \\ :empty) do
    model
    |> cast(params, @required_fields, @optional_fields)
  end
end
Salesroom answered 23/11, 2015 at 12:7 Comment(0)
S
7

According to the tests for the library:

https://github.com/bryanjos/geo/blob/351ee6c4f8ed24541c9c2908f615e7b0a238f010/test/geo/ecto_test.exs#L100

You need to pass a Geo.Point to your changeset function:

changeset = Place.changeset(%Place{}, %{coordinates: %Geo.Point{coordinates: {49.44, 17.87}})

You can read more about custom ecto types in [the docs].(https://hexdocs.pm/ecto/Ecto.Type.html#content)

Springs answered 23/11, 2015 at 12:11 Comment(6)
Could you tell me how can I map {coordinates: {latitude: 49.44, longitude: 17.87}} to extract latitude & longitude into %Geo.Point{} in right format?Salesroom
%Geo.Point(coordinates: {get_in(coords_map.coordinates.latitude), get_in(coords_map.coordinates.longitude)}) elixir-lang.org/docs/stable/elixir/Kernel.html#get_in/2Springs
when I have more params like coords_map = %{name: "test", coordinates: %{latitude: 49.44, longitude: 17.87}} I would like to concat %Geo.Point to coordinates param, is for it some easy way?Salesroom
coords_map = map.coordinates then %Geo.Point(coordinates: {get_in(coords_map.latitude), get_in(coords_map.longitude)}Springs
I can't use get_in/2 inside match in controller, so could you tell me if I can wrap coordinates by %Geo.Point inside controller match def create(conn, %{"notify" => notify_params}) do ? I want pass also other params.Salesroom
@Salesroom You can pattern match parameters. def create(conn, %{"notify" => %{"coordinates" => %{"longitute" => longitude, "latitide" => latitude}} = notify_params) If that doesn't make sense or fix your issue please create a new question that explains your issue more clearly.Springs
E
0

For future reader, there is also geo_postgis, by the same author and based on geo, which is a postgrex extension and works with ecto.

Endometrium answered 6/6, 2019 at 16:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.