Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Ecto Embedded Schemas

Ecto Embedded Schemas

We’ll take a look at how Ecto’s embedded schemas can help us persist and retrieve structured and meaningful data using database JSON columns.

This is a lightning talk I gave at the May 2018 Montreal Elixir Meetup hosted by Mirego.

8c4cee1129bc11fbe9a0b9379dce2cb1?s=128

Rémi Prévost

May 09, 2018
Tweet

Transcript

  1. Ecto Embedded Schemas Rémi Prévost Montreal Elixir Meetup 2018/05/09

  2. None
  3. params = %{ "author_name" => "Rémi Prévost", "published" => true,

    "title" => %{ "en" => "My new article in english",
 "fr" => "Mon nouvel article en français" } } %App.Blog.Article{} |> App.Blog.Article.changeset(params) |> App.Repo.insert!()
  4. Schema-less data Map → JSON → Map

  5. defmodule App.Blog.Article do use Ecto.Schema import Ecto.Changeset schema "articles" do

    field(:author_name, :string) field(:published, :boolean) field(:title, :map) end def changeset(%__MODULE__{} = record, params) do record |> cast(~w(author_name published title)a, params) |> validate_required(~w(author_name title)a) |> validate_change(:title, &validate_nested_french_value/2) end
 defp validate_nested_french_value(field, %{"fr" => fr}) when fr != "", do: [] defp validate_nested_french_value(field, _) do [{field, "must specify french value"}] end end
  6. App.Blog.Article |> App.Repo.get(1) %App.Blog.Article{ id: 1, author_name: "Rémi Prévost", published:

    true, title: %{ en: "My new article in english",
 fr: "Mon nouvel article in english" } }
  7. defmodule App.Payments.Transaction do use Ecto.Schema import Ecto.Changeset schema "payment_transations" do

    field(:gateway_response, :map) belongs_to(:order_id, App.Order) end def changeset(%__MODULE__{} = record, params) do record |> cast(~w(order_id gateway_response)a, params) |> validate_required(~w(order_id)a) end end
  8. Embedded schema Schema → JSON → Schema

  9. defmodule App.Blog.Article do use Ecto.Schema import Ecto.Changeset schema "articles" do

    field(:author_name, :string)
 field(:published, :boolean) embeds_one(:title, App.Translations.Translated) end def changeset(%__MODULE__{} = record, params) do record |> cast(~w(author_name published)a, params) |> validate_required(~w(author_name)a) |> cast_embed(:title, required: true) end end
  10. defmodule App.Translations.Translated do use Ecto.Schema import Ecto.Changeset embedded_schema do field(:en,

    :string) field(:fr, :string) end def changeset(%__MODULE__{} = record, params) do record |> cast(~w(en fr)a, params) |> validate_required(~w(fr)a) end end
  11. App.Blog.Article |> App.Repo.get(1) %App.Blog.Article{ id: 1, author_name: "Rémi Prévost",
 published:

    true, title: %App.Translations.Translated{ id: "602975a2-bfbd-4c48-9d60-0b955ccc4bc7", en: "My new article in english", fr: "Mon nouvel article en français" } }
  12. That’s it! Ecto.Schema and Ecto.Changeset are awesome.