Découverte d’ Ecto pour utiliser Postgres avec Phoenix. Le cours sur Ecto proposé par Productive Programmer nous donne la trame de cet article.
Après avoir montré comment créer une application phoenix pas à pas. Nous allons maintenant utiliser Ecto pour ajouter une base de données Postgres à nos projets Phoenix.
Création du projet Customer
Nous créons le projet dans le dossier :
- C:\CarbonX1\Phoenix\Projets
Vérifions l’installation de postgreSQL :
- psql –version
Puis nous activons la commande de création du projet :
- mix phx.new customer ‘customer est le nom du projet
C:\CarbonX1\Phoenix\Projets>psql --version psql (PostgreSQL) 15.4 C:\CarbonX1\Phoenix\Projets>mix phx.new customer * creating customer/config/config.exs * creating customer/config/dev.exs * creating customer/config/prod.exs * creating customer/config/runtime.exs * creating customer/config/test.exs * creating customer/lib/customer/application.ex * creating customer/lib/customer.ex * creating customer/lib/customer_web/controllers/error_json.ex * creating customer/lib/customer_web/endpoint.ex * creating customer/lib/customer_web/router.ex * creating customer/lib/customer_web/telemetry.ex * creating customer/lib/customer_web.ex * creating customer/mix.exs * creating customer/README.md * creating customer/.formatter.exs * creating customer/.gitignore * creating customer/test/support/conn_case.ex * creating customer/test/test_helper.exs * creating customer/test/customer_web/controllers/error_json_test.exs * creating customer/lib/customer/repo.ex * creating customer/priv/repo/migrations/.formatter.exs * creating customer/priv/repo/seeds.exs * creating customer/test/support/data_case.ex * creating customer/lib/customer_web/controllers/error_html.ex * creating customer/test/customer_web/controllers/error_html_test.exs * creating customer/lib/customer_web/components/core_components.ex * creating customer/lib/customer_web/controllers/page_controller.ex * creating customer/lib/customer_web/controllers/page_html.ex * creating customer/lib/customer_web/controllers/page_html/home.html.heex * creating customer/test/customer_web/controllers/page_controller_test.exs * creating customer/lib/customer_web/components/layouts/root.html.heex * creating customer/lib/customer_web/components/layouts/app.html.heex * creating customer/lib/customer_web/components/layouts.ex * creating customer/priv/static/images/logo.svg * creating customer/lib/customer/mailer.ex * creating customer/lib/customer_web/gettext.ex * creating customer/priv/gettext/en/LC_MESSAGES/errors.po * creating customer/priv/gettext/errors.pot * creating customer/priv/static/robots.txt * creating customer/priv/static/favicon.ico * creating customer/assets/js/app.js * creating customer/assets/vendor/topbar.js * creating customer/assets/css/app.css * creating customer/assets/tailwind.config.js * creating customer/assets/vendor/heroicons/LICENSE.md * creating customer/assets/vendor/heroicons/UPGRADE.md * extracting customer/assets/vendor/heroicons/optimized Fetch and install dependencies? [Yn] y * running mix deps.get * running mix assets.setup * running mix deps.compile We are almost there! The following steps are missing: $ cd customer Then configure your database in config/dev.exs and run: $ mix ecto.create Start your Phoenix app with: $ mix phx.server You can also run your app inside IEx (Interactive Elixir) as: $ iex -S mix phx.server C:\CarbonX1\Phoenix\Projets>
Nous suivons les instructions et nous rendant dans le dossier customer :
- cd customer
Puis nous ouvrons VS Code avec :
- code .
Les paramètres de connexion à la base de données sont notés dans dev.exs, fichier de configuration en mode developper :
- CUSTOMER/config/dev.exs
Et nous voyons les valeurs choisies pour username et password :
# Configure your database config :customer, Customer.Repo, username: "postgres", password: "postgres", hostname: "localhost", database: "customer_dev", stacktrace: true, show_sensitive_data_on_connection_error: true, pool_size: 10
pour vérifier les paramètres de configuration de la base de données postgreSQL nous utilisons la commande en prenant « postgres » comme paramètre c’est à dire le username dans la configuration ci-dessus.
- psql -U postgres ‘pour se connecter en tant qu’utilisateur username: postgres
- \c ‘pour vérifier la connexion
- \q ‘pour quitter postgres
C:\CarbonX1\Phoenix\Projets\customer>psql -U postgres Mot de passe pour l'utilisateur postgres : psql (15.4) Attention : l'encodage console (850) diffère de l'encodage Windows (1252). Les caractères 8 bits peuvent ne pas fonctionner correctement. Voir la section « Notes aux utilisateurs de Windows » de la page référence de psql pour les détails. Saisissez « help » pour l'aide. postgres=# \c Vous êtes maintenant connecté à la base de données « postgres » en tant qu'utilisateur « postgres ». postgres=# \q C:\CarbonX1\Phoenix\Projets\customer>
Nous avons maintenant vérifier que la configuration de postgreSQL est conforme à ce que nous avons indiqué pour notre projet Customer.
Si nous activons le projet directement, nous aurons une erreur car la base de données n’a pas été créée :
- mix phx.server ‘activer le serveur
- http://localhost:4000 ‘aller sur la page dans le navigateur
Ecto create pour utiliser la base de données Postgres avec Phoenix
La base de données doit être créée avec la commande :
- mix ecto.create
Relançons le serveur puis allons sur la page :
- iex -S mix phx.server ‘activation du serveur dans iex
- http://localhost:4000 ‘activation de la page
Nous avons maintenant la page standard Phoenix :
Nous pouvons maintenant vérifier notre connexion à la base de données dans postgres en ligne de commande :
- psql -U postgres ‘ pour ouvrir une session vers la base de données avec l’utilisateur postgres
- \c customer_dev ‘ pour se connecter à la base customer_dev
- \q ‘pour quitter psql
C:\CarbonX1\Phoenix\Projets\customer>psql -U postgres Mot de passe pour l'utilisateur postgres : psql (15.4) Attention : l'encodage console (850) diffère de l'encodage Windows (1252). Les caractères 8 bits peuvent ne pas fonctionner correctement. Voir la section « Notes aux utilisateurs de Windows » de la page référence de psql pour les détails. Saisissez « help » pour l'aide. postgres=# \c customer_dev Vous êtes maintenant connecté à la base de données « customer_dev » en tant qu'utilisateur « postgres ». customer_dev=# \q C:\CarbonX1\Phoenix\Projets\customer>
La base de données cutomer_dev est créée mais nous n’avons encore ajouté aucune table.
Ecto, utiliser le schéma de données pour Postgres avec Phoenix
Ecto propose des outils pour générer le code Phoenix et aider à la création des changments dans la base de données.
Nous devons nous placer dans le dossier du projet :
- cd C:\CarbonX1\Phoenix\Projets\Customer
Pour créer les colonnes de la table et la table, nous utilisons le générateur phx.gen.schema auquel nous donnons le nom du schema [Customer] (le module Phoenix pour l’accès à notre table) puis le nom de la table [customers] suivi des colonnes [first_name, last_name, email, age] avec pour chaque colonne son type de données [string ou integer] :
- mix phx.gen.schema Customer customers first_name:string last_name:string email:string age:integer
C:\CarbonX1\Phoenix\Projets\customer>mix phx.gen.schema Customer customers first_name:string last_name:string email:string age:integer * creating lib/customer/customer.ex * creating priv/repo/migrations/20231123134225_create_customers.exs Remember to update your repository by running migrations: $ mix ecto.migrate C:\CarbonX1\Phoenix\Projets\customer>
Cette commande va créer 2 fichiers :
- lib/cutomer/customer.ex ‘ le module Customer
- priv/repo/migrations/20231123134225_create_customers.exs ‘le code de la migration.
Pour modifier le schema de la table Ecto propose de faire des migrations. Le fichier de migration est créé par la commande mix phx.gen.schema. Le fichier de migration a un numéro de migration lié à la date : 20231123134225.
Regardons les fichiers générés :
Le fichier avec le module Customer : lib/customer/customer.ex :
defmodule Customer.Customer do use Ecto.Schema import Ecto.Changeset schema "customers" do field :first_name, :string field :last_name, :string field :email, :string field :age, :integer timestamps() end @doc false def changeset(customer, attrs) do customer |> cast(attrs, [:first_name, :last_name, :email, :age]) |> validate_required([:first_name, :last_name, :email, :age]) end end
Le module Customer du projet Customer est nommé Customer.Customer.
priv/repo/migrations/20231123134225_create_customers.exs :
defmodule Customer.Repo.Migrations.CreateCustomers do use Ecto.Migration def change do create table(:customers) do add :first_name, :string add :last_name, :string add :email, :string add :age, :integer timestamps() end end end
L’exécution de la migration se fait avec :
- mix ecto.migrate ‘exécute toutes les migrations situées dans priv/repo/migrations/
C:\CarbonX1\Phoenix\Projets\customer>mix ecto.migrate Compiling 1 file (.ex) Generated customer app 14:45:09.653 [info] == Running 20231123134225 Customer.Repo.Migrations.CreateCustomers.change/0 forward 14:45:09.655 [info] create table customers 14:45:09.684 [info] == Migrated 20231123134225 in 0.0s C:\CarbonX1\Phoenix\Projets\customer>
On peut vérifier dans PostgreSQL les changements qui ont eu lieu :
- psql -U postgres ‘ se connecter à la base avec l’utilisateur postgres
- \connect customer_dev ‘se connecter à notre base de données customer_dev
- \d ‘ liste les tables de la base customer_dev
- \d customers ‘ liste les colonnes de la table customers
- \q ‘quitter psql
C:\CarbonX1\Phoenix\Projets\customer>psql -U postgres Mot de passe pour l'utilisateur postgres : psql (15.4) Attention : l'encodage console (850) diffère de l'encodage Windows (1252). Les caractères 8 bits peuvent ne pas fonctionner correctement. Voir la section « Notes aux utilisateurs de Windows » de la page référence de psql pour les détails. Saisissez « help » pour l'aide. postgres=# \connect customer_dev Vous êtes maintenant connecté à la base de données « customer_dev » en tant qu'utilisateur « postgres ». customer_dev=# \d Liste des relations SchÚma | Nom | Type | PropriÚtaire --------+-------------------+----------+-------------- public | customers | table | postgres public | customers_id_seq | sÚquence | postgres public | schema_migrations | table | postgres (3 lignes) customer_dev=# \d customers Table ½ public.customers ╗ Colonne | Type | Collationnement | NULL-able | Par dÚfaut -------------+--------------------------------+-----------------+-----------+--------------------------------------- id | bigint | | not null | nextval('customers_id_seq'::regclass) first_name | character varying(255) | | | last_name | character varying(255) | | | email | character varying(255) | | | age | integer | | | inserted_at | timestamp(0) without time zone | | not null | updated_at | timestamp(0) without time zone | | not null | Index : "customers_pkey" PRIMARY KEY, btree (id) customer_dev=# \q C:\CarbonX1\Phoenix\Projets\customer>
On note que Phoenix a ajouté :
- une colonne id:bigint qui est l’identifiant unique qui sera généré automatiquement pour chaque enregistrement dans la table.
- deux colonnes timestamp : inserted_at et updated_at
Utiliser le changeset Ecto avec Postgres et Phoenix
Nous allons utiliser la version interactive d’Elixir avec iex. Nous ouvrons le terminal.
- iex -S mix
pour simplifier l’écriture de code sans avoir à rappeler Customer.Customer devant les fonctions que nous allons utiliser, nous créons l’alias Customer.Customer :
- alias Customer.Customer
Nous pouvons maintenant appeler la fonction changeset de Customer. Cette fonction reçoit le schéma sous la forme d’une structure Customer et les données qui sont les attributs.
@doc false def changeset(customer, attrs) do customer |> cast(attrs, [:first_name, :last_name, :email, :age]) |> validate_required([:first_name, :last_name, :email, :age]) end
Dans changeset, nous avons la ligne validate_required([:first_name, :last_name, :email, :age]), qui donne la liste des champs obligatoires. Ici les 4 champs sont obligatoires.
Nous pouvons travailler avec le changeset dans iex, en créant une variable changeset :
- changeset= Customer.changeset(%Customer{}, %{first_name: « Eric », last_name: « Durand », email: « eric.durand@gmail.com »})
- changeset.errors
- changeset.valid?
- changeset.changes
C:\CarbonX1\Phoenix\Projets\customer>iex -S mix Erlang/OTP 26 [erts-14.0.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit:ns] Interactive Elixir (1.15.5) - press Ctrl+C to exit (type h() ENTER for help) iex(1)> alias Customer.Customer Customer.Customer iex(2)> changeset= Customer.changeset(%Customer{}, %{first_name: "Eric", last_name: "Durand", email: "eric.durand@gmail. com"}) #Ecto.Changeset< action: nil, changes: %{ first_name: "Eric", last_name: "Durand", email: "eric.durand@gmail.com" }, errors: [age: {"can't be blank", [validation: :required]}], data: #Customer.Customer<>, valid?: false > iex(3)>
L’absence de la propriété age donne une erreur.
Le contrôle des données se fait dans changeset avec validate
La liste validate_required donne les variables obligatoires. Nous pouvons retirer age des variables obligatoires dans :
- validate_required([:first_name, :last_name, :email, :age]) ‘avant la modification du validate
- validate_required([:first_name, :last_name, :email]) ‘après la suppresion d’age dans la liste
Mettons à jour le fichier puis relançons la compilation dans iex :
- clear ‘efface l’ecran
- recompile() ‘recompile le code
Voyons ce que donne ce changement dans iex :
- changeset= Customer.changeset(%Customer{}, %{first_name: « Eric », last_name: « Durand », email: « eric.durand@gmail.com »})
- changeset.errors ‘quand il n’y a pas d’erreur nous avons une liste vide
- changeset.valid? ‘donne true ou false pour indiquer si le changeset est valide
- changeset.changes ‘la liste des changements
iex(4)> recompile() Compiling 1 file (.ex) :ok iex(5)> changeset= Customer.changeset(%Customer{}, %{first_name: "Eric", last_name: "Durand", email: "eric.durand@gmail. com"}) #Ecto.Changeset< action: nil, changes: %{ first_name: "Eric", last_name: "Durand", email: "eric.durand@gmail.com" }, errors: [], data: #Customer.Customer<>, valid?: true > iex(6)> changeset.valid? true iex(7)> changeset.changes %{first_name: "Eric", last_name: "Durand", email: "eric.durand@gmail.com"} iex(8)> changeset.errors [] iex(9)>
On peut ajouter des règles de contrôle complémentaires à notre fonction changeset :
- validate_length(:first_name, min: 3)
- validate_length(:first_name, max: 20)
- validate_format(:email,~r/@/) ‘vérifie que l’email contient le caractère ‘@’ par regex ‘~r’
Lorsqu’on fait des changements dans le code, on peut relancer iex dans la fenêtre terminale avec :
- clear
- recompile()
on peut demander au changeset d’afficher les erreurs sur un champ :
- changeset.errors[:first_name]
La documentation de changeset Ecto donne la liste de toutes les validations possibles.
Modification de la base de données avec Changeset Ecto
Lors de la création de notre schéma de base de données, nous avons créé le Module Customer. Un autre fichier appelé Repo.ex a aussi été créé. Ce module situé en lib/customer/repo.ex est un connecteur vers la base de données PostgreSQL. :
defmodule Customer.Repo do use Ecto.Repo, otp_app: :customer, adapter: Ecto.Adapters.Postgres end
Insertion des données directement avec Repo
Nous allons utiliser iex pour créer les modifications dans la base de données. Commençons par importer Repo et Customer avec alias :
- cd C:\CarbonX1\Phoenix\Projets\Customer
- iex -S mix
- alias Customer.{Repo, Customer}
Avec Repo, nous pouvons inserer des données dans la base de données directement :
- Repo.insert(%Customer{email: « customer1@gmail.com »})
Cela montre que nous pouvons inserer des données avec Repo directement dans la base de données sans utiliser changeset. Biensûr, changeset est necessaire pour vérifier que les données sont valides avant de les insérer dans la base de données.
Nous pouvons lire dans la base de données avec Repo :
- customers = Repo.all(Customer)
Nous avons maintenent dans la variable customers les données en provenance de la base de données.
C:\CarbonX1\Phoenix\Projets\customer>iex -S mix Erlang/OTP 26 [erts-14.0.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit:ns] Interactive Elixir (1.15.5) - press Ctrl+C to exit (type h() ENTER for help) iex(1)> alias Customer.{Repo, Customer} [Customer.Repo, Customer.Customer] iex(2)> Repo.insert(%Customer{email: "customer1@gmail.com"}) [debug] QUERY OK source="customers" db=14.3ms decode=7.5ms queue=2.6ms idle=1383.7ms INSERT INTO "customers" ("email","inserted_at","updated_at") VALUES ($1,$2,$3) RETURNING "id" ["customer1@gmail.com", ~N[2023-11-24 09:59:33], ~N[2023-11-24 09:59:33]] ↳ anonymous fn/4 in :elixir.eval_external_handler/1, at: src/elixir.erl:376 {:ok, %Customer.Customer{ __meta__: #Ecto.Schema.Metadata<:loaded, "customers">, id: 1, first_name: nil, last_name: nil, email: "customer1@gmail.com", age: nil, inserted_at: ~N[2023-11-24 09:59:33], updated_at: ~N[2023-11-24 09:59:33] }} iex(3)> customers = Repo.all(Customer) [debug] QUERY OK source="customers" db=1.8ms queue=1.0ms idle=1012.3ms SELECT c0."id", c0."first_name", c0."last_name", c0."email", c0."age", c0."inserted_at", c0."updated_at" FROM "customers" AS c0 [] ↳ anonymous fn/4 in :elixir.eval_external_handler/1, at: src/elixir.erl:376 [ %Customer.Customer{ __meta__: #Ecto.Schema.Metadata<:loaded, "customers">, id: 1, first_name: nil, last_name: nil, email: "customer1@gmail.com", age: nil, inserted_at: ~N[2023-11-24 09:59:33], updated_at: ~N[2023-11-24 09:59:33] } ] iex(4)>
Utilisation de changeset pour contrôler les données
Si nous prenons un changeset avec des données valides :
- changeset= Customer.changeset(%Customer{}, %{first_name: « Eric », last_name: « Durand », email: « eric.durand@gmail.com »})
- changeset.valid?
- Repo.insert(changeset) ‘pour inserer notre changeset dans la base de données
- customers = Repo.all(Customer)
- customers
iex(5)> changeset= Customer.changeset(%Customer{}, %{first_name: "Eric", last_name: "Durand", email: "eric.durand@gmail. com"}) #Ecto.Changeset< action: nil, changes: %{ email: "eric.durand@gmail.com", first_name: "Eric", last_name: "Durand" }, errors: [], data: #Customer.Customer<>, valid?: true > iex(6)> changeset.valid? true iex(7)> Repo.insert(changeset) [debug] QUERY OK source="customers" db=3.9ms queue=1.6ms idle=1550.7ms INSERT INTO "customers" ("email","first_name","last_name","inserted_at","updated_at") VALUES ($1,$2,$3,$4,$5) RETURNING "id" ["eric.durand@gmail.com", "Eric", "Durand", ~N[2023-11-24 10:03:06], ~N[2023-11-24 10:03:06]] ↳ anonymous fn/4 in :elixir.eval_external_handler/1, at: src/elixir.erl:376 {:ok, %Customer.Customer{ __meta__: #Ecto.Schema.Metadata<:loaded, "customers">, id: 2, first_name: "Eric", last_name: "Durand", email: "eric.durand@gmail.com", age: nil, inserted_at: ~N[2023-11-24 10:03:06], updated_at: ~N[2023-11-24 10:03:06] }} iex(8)> customers = Repo.all(Customer) [debug] QUERY OK source="customers" db=4.1ms queue=0.1ms idle=1034.9ms SELECT c0."id", c0."first_name", c0."last_name", c0."email", c0."age", c0."inserted_at", c0."updated_at" FROM "customers" AS c0 [] ↳ anonymous fn/4 in :elixir.eval_external_handler/1, at: src/elixir.erl:376 [ %Customer.Customer{ __meta__: #Ecto.Schema.Metadata<:loaded, "customers">, id: 1, first_name: nil, last_name: nil, email: "customer1@gmail.com", age: nil, inserted_at: ~N[2023-11-24 09:59:33], updated_at: ~N[2023-11-24 09:59:33] }, %Customer.Customer{ __meta__: #Ecto.Schema.Metadata<:loaded, "customers">, id: 2, first_name: "Eric", last_name: "Durand", email: "eric.durand@gmail.com", age: nil, inserted_at: ~N[2023-11-24 10:03:06], updated_at: ~N[2023-11-24 10:03:06] } ] iex(9)> customers [ %Customer.Customer{ __meta__: #Ecto.Schema.Metadata<:loaded, "customers">, id: 1, first_name: nil, last_name: nil, email: "customer1@gmail.com", age: nil, inserted_at: ~N[2023-11-24 09:59:33], updated_at: ~N[2023-11-24 09:59:33] }, %Customer.Customer{ __meta__: #Ecto.Schema.Metadata<:loaded, "customers">, id: 2, first_name: "Eric", last_name: "Durand", email: "eric.durand@gmail.com", age: nil, inserted_at: ~N[2023-11-24 10:03:06], updated_at: ~N[2023-11-24 10:03:06] } ] iex(10)>
Lorsque le changeset n’est pas valide, l’insertion va échouer.
Ajoutons dans nos règles de validation le contrôle sur l’email dans la fonction changeset de Customer :
- validate_format(:email,~r/@/) ‘(ligne 19) vérifie que l’email contient le caractère ‘@’ par regex ‘~r’
defmodule Customer.Customer do use Ecto.Schema import Ecto.Changeset schema "customers" do field :first_name, :string field :last_name, :string field :email, :string field :age, :integer timestamps() end @doc false def changeset(customer, attrs) do customer |> cast(attrs, [:first_name, :last_name, :email, :age]) |> validate_required([:first_name, :last_name, :email]) |> validate_format(:email,~r/@/) end end
Nous compilons et poursuivons les tests :
- clear
- recompile()
- changeset= Customer.changeset(%Customer{}, %{first_name: « Franck », last_name: « Dupond », email: « emailAvecUneErreurGmail.com »})
- changeset.valid?
- changeset.errors
- Repo.insert(changeset) ‘pour inserer notre changeset dans la base de données
L’insertion est refusée grâce au contrôle de format sur l’email :
iex(13)> recompile() Compiling 1 file (.ex) :ok iex(14)> changeset= Customer.changeset(%Customer{}, %{first_name: "Franck", last_name: "Dupond", email: "emailAvecUneErr eurGmail.com"}) #Ecto.Changeset< action: nil, changes: %{ email: "emailAvecUneErreurGmail.com", first_name: "Franck", last_name: "Dupond" }, errors: [email: {"has invalid format", [validation: :format]}], data: #Customer.Customer<>, valid?: false > iex(15)> changeset.valid? false iex(16)> changeset.errors [email: {"has invalid format", [validation: :format]}] iex(17)> Repo.insert(changeset) {:error, #Ecto.Changeset< action: :insert, changes: %{ email: "emailAvecUneErreurGmail.com", first_name: "Franck", last_name: "Dupond" }, errors: [email: {"has invalid format", [validation: :format]}], data: #Customer.Customer<>, valid?: false >} iex(18)>
Utilisation Query pour accéder aux données
Ecto donne aussi accès à un requêteur avec Query :
- clear
- import Ecto.Query
- Repo.all(from c in Customer, select: c.email) ‘pour récuperer que les emails
- listEmail = Repo.all(from c in Customer, select: c.email)
- listEmail
Nous obtenons tous les emails de la base de données.
iex(19)> import Ecto.Query Ecto.Query iex(20)> Repo.all(from c in Customer, select: c.email) [debug] QUERY OK source="customers" db=0.3ms queue=0.4ms idle=1639.2ms SELECT c0."email" FROM "customers" AS c0 [] ↳ anonymous fn/4 in :elixir.eval_external_handler/1, at: src/elixir.erl:376 ["customer1@gmail.com", "eric.durand@gmail.com"] iex(21)> listEmail = Repo.all(from c in Customer, select: c.email) [debug] QUERY OK source="customers" db=0.4ms idle=1402.9ms SELECT c0."email" FROM "customers" AS c0 [] ↳ anonymous fn/4 in :elixir.eval_external_handler/1, at: src/elixir.erl:376 ["customer1@gmail.com", "eric.durand@gmail.com"] iex(22)> listEmail ["customer1@gmail.com", "eric.durand@gmail.com"] iex(23)>
Pour obtenir un seul record, nous avons :
- eric = Repo.one(from c in Customer, where: c.email== « eric.durand@gmail.com ») ‘pour récuperer eric par son email
- eric ‘la variable contient le record « Eric Durand »
iex(23)> eric = Repo.one(from c in Customer, where: c.email== "eric.durand@gmail.com") [debug] QUERY OK source="customers" db=3.9ms queue=3.5ms idle=1241.4ms SELECT c0."id", c0."first_name", c0."last_name", c0."email", c0."age", c0."inserted_at", c0."updated_at" FROM "customers" AS c0 WHERE (c0."email" = 'eric.durand@gmail.com') [] ↳ anonymous fn/4 in :elixir.eval_external_handler/1, at: src/elixir.erl:376 %Customer.Customer{ __meta__: #Ecto.Schema.Metadata<:loaded, "customers">, id: 2, first_name: "Eric", last_name: "Durand", email: "eric.durand@gmail.com", age: nil, inserted_at: ~N[2023-11-24 10:03:06], updated_at: ~N[2023-11-24 10:03:06] } iex(24)> eric %Customer.Customer{ __meta__: #Ecto.Schema.Metadata<:loaded, "customers">, id: 2, first_name: "Eric", last_name: "Durand", email: "eric.durand@gmail.com", age: nil, inserted_at: ~N[2023-11-24 10:03:06], updated_at: ~N[2023-11-24 10:03:06] } iex(25)>
La modification du record Eric Durand se fait avec la création d’un changeset de modification :
- changeset = Customer.changeset(%Customer{}, params) ‘version précédente
Pour modiufier l’adresse email d’Eric Durand :
- clear
- changeset = Customer.changeset(eric, %{email: « e.durand@gmail »})
- changeset.valid? ‘vérifier si notre changeset est valide
- changeset.data ‘voir nos données avant changement
- Repo.update(changeset) ‘modifier la base de données avec notre changeset
- Repo.all(Customer) ‘pour voir les changements dans la base de données
iex(26)> changeset = Customer.changeset(eric, %{email: "e.durand@gmail"}) #Ecto.Changeset< action: nil, changes: %{email: "e.durand@gmail"}, errors: [], data: #Customer.Customer<>, valid?: true > iex(27)> changeset.valid? true iex(28)> changeset.data %Customer.Customer{ __meta__: #Ecto.Schema.Metadata<:loaded, "customers">, id: 2, first_name: "Eric", last_name: "Durand", email: "eric.durand@gmail.com", age: nil, inserted_at: ~N[2023-11-24 10:03:06], updated_at: ~N[2023-11-24 10:03:06] } iex(29)> Repo.update(changeset) [debug] QUERY OK source="customers" db=8.9ms queue=4.8ms idle=1233.1ms UPDATE "customers" SET "email" = $1, "updated_at" = $2 WHERE "id" = $3 ["e.durand@gmail", ~N[2023-11-24 10:21:01], 2] ↳ anonymous fn/4 in :elixir.eval_external_handler/1, at: src/elixir.erl:376 {:ok, %Customer.Customer{ __meta__: #Ecto.Schema.Metadata<:loaded, "customers">, id: 2, first_name: "Eric", last_name: "Durand", email: "e.durand@gmail", age: nil, inserted_at: ~N[2023-11-24 10:03:06], updated_at: ~N[2023-11-24 10:21:01] }} iex(30)> Repo.all(Customer) [debug] QUERY OK source="customers" db=1.2ms queue=0.1ms idle=1905.4ms SELECT c0."id", c0."first_name", c0."last_name", c0."email", c0."age", c0."inserted_at", c0."updated_at" FROM "customers" AS c0 [] ↳ anonymous fn/4 in :elixir.eval_external_handler/1, at: src/elixir.erl:376 [ %Customer.Customer{ __meta__: #Ecto.Schema.Metadata<:loaded, "customers">, id: 1, first_name: nil, last_name: nil, email: "customer1@gmail.com", age: nil, inserted_at: ~N[2023-11-24 09:59:33], updated_at: ~N[2023-11-24 09:59:33] }, %Customer.Customer{ __meta__: #Ecto.Schema.Metadata<:loaded, "customers">, id: 2, first_name: "Eric", last_name: "Durand", email: "e.durand@gmail", age: nil, inserted_at: ~N[2023-11-24 10:03:06], updated_at: ~N[2023-11-24 10:21:01] } ] iex(31)>
Conclusion
Nous avons fait un petit tour sur l’utilisation d’Ecto avec :
- une présentation du changeset
- l’utilisation de Repo