Zmiana technologii z Javy na Elixira nie spowodowała zmniejszenia ilości ciekawego kodu w projekcie. Po prostu sam go teraz więcej produkuję.
Mamy taki kod:
def update(conn, %{settings: settings}, %{user_id: id, platform_id: platform_id}) do
user = User.get!(id)
with {:ok, user} <- User.update_settings(user, settings),
{:ok, platform} <- Platforms.get_platform(platform_id),
{:ok, _} <- is_binary(settings[:password]) |> Service.queue_password_changed_email(user, platform)
do
render(conn, "show.json", user: user)
end
end
Jeżeli użytkownik zmienił hasło, to wyślij email. Niestety jest w tym kodzie mały babol, bo jeżeli użytkownik jest tworzony „za zaproszeniem”, to już w momencie wysłania maila z zaproszeniem tworzymy użytkownika i później, jak się rejestruje, to dostaje maila z informacją o zmianie hasła. Zatem zmieniam na:
def update(conn, %{settings: settings}, %{user_id: id, platform_id: platform_id}) do
user = User.get!(id)
is_password_not_nil = !is_nil(user.encrypted_password)
with {:ok, user} <- User.update_settings(user, settings),
{:ok, platform} <- Platforms.get_platform(platform_id)
do
if (is_binary(settings[:password])) do
Service.queue_password_changed_email(is_password_not_nil, user, platform)
end
render(conn, "show.json", user: user)
end
end
ale nie przechodzi CR, bo choć działa, to warunek w if jest rozbity na if-a i pierwszy, opcjonalny, parametr funkcji kolejkującej. W dodatku jakieś dodatkowe zmienne i w ogóle nie po elixirowemu. Zmieniam:
def update(conn, %{settings: settings}, %{user_id: id, platform_id: platform_id}) do
user = User.get!(id)
with {:ok, user} <- User.update_settings(user, settings),
{:ok, platform} <- Platforms.get_platform(platform_id)
do
if (!is_nil(user.encrypted_password) && is_binary(settings[:password])) do
Service.queue_password_changed_email(user, platform)
end
render(conn, "show.json", user: user)
end
end
Przestało działać. noszkurwaface.jpg Debugger i jedziemy. Wchodzi w if-a, nawet jak pierwszy warunek jest false
. Po chwili olśnienie:
def update(conn, %{settings: settings}, %{user_id: id, platform_id: platform_id}) do
user = User.get!(id)
is_password_not_nil = !is_nil(user.encrypted_password)
with {:ok, user} <- User.update_settings(user, settings),
{:ok, platform} <- Platforms.get_platform(platform_id)
do
if (is_password_not_nil and is_binary(settings[:password])) do
Service.queue_password_changed_email(user, platform)
end
render(conn, "show.json", user: user)
end
end
Elixir ma dwa rodzaje operatorów logicznych. Normalne tzn. && || itd. oraz „dla pascalowców” and
, or
, not
. Te pierwsze przyjmą wszystko, a te drugie tylko wartości true
i false
. Rzecz w tym, że te pierwsze pozwalają na porównanie różnych typów i czasami wychodzą „głupoty”. Jednak jest tu cudowniejszy babol. W trzecim przypadku błąd powrócił, ponieważ sprawdzenie, czy zaszyfrowane hasło istnieje, odbywało się po zapisie do bazy danych. Uroki używania with
:D