defmodule Mango.CRM.Customer do
use Ecto.Schema
import Ecto.Changeset
alias Mango.CRM.Customer
import Comeonin.Bcrypt, only: [hashpwsalt: 1]
schema "customers" do
field :email, :string
field :name, :string
field :password, :string, virtual: true
field :password_hash, :string
field :phone, :string
field :residence_area, :string
timestamps()
end
@doc false
def changeset(%Customer{} = customer, attrs) do
customer
|> cast(attrs, [:name, :email, :phone, :residence_area, :password])
|> validate_required([:name, :email, :phone, :residence_area, :password])
|> validate_format(:email, ~r/@/, message: "is invalid")
|> validate_length(:password, min: 6, max: 100)
|> unique_constraint(:email)
|> put_hashed_password()
end
defp put_hashed_password(changeset) do
case changeset.valid? do
true ->
changes = changeset.changes
put_change(changeset, :password_hash, hashpwsalt(changes.password))
_ ->
changeset
end
end
end
When I hover the cursor over lowercase changeset inside put_hashed_password private function, it shows the following hover overlay
which means it’s the changeset function from the same file.
But I don’t see anything as changes in the changeset function, then where does this changeset.changes come from?
As @NobbZ said, changeset is the local variable but the code editor is confused, because in Elixir function’s parenthesis are optional.
If you don’t wanna confuse the editor, write the function as follows,
defp put_hashed_password(ch) do
case ch.valid? do
true ->
changes = ch.changes
put_change(ch, :password_hash, hashpwsalt(changes.password))
_ ->
ch
end
end
No, the changes key is present on only Ecto.Changeset struct.
In your terminal inside the project directory, run iex -S mix and then %Ecto.Changeset{},
you’ll get #Ecto.Changeset<action: nil, changes: %{}, errors: [], data: nil, valid?: false>
Reading your code again, you’re actually passing the customer which is an Ecto.Changeset struct conforming to the %Customer{} struct, while matched as %Customer{} = customer (argument in the changeset function).
It means this changeset will allow only the keys specified in the Mango.CRM.Customer{} struct (which you aliased as alias Mango.CRM.Customer) and some other default keys, like changes, errors, valid? etc.
In that case if you write the put_hashed_password as follows, it will be clearer and less confusing, both for you and the code editor.
defp put_hashed_password(customer) do
case customer.valid? do
true ->
changes = customer.changes
put_change(customer, :password_hash, hashpwsalt(changes.password))
_ ->
customer
end
en