Хотя правильным способом предотвращения действий с некоторыми «записями флешки» было бы изменение базы данных для отклонения таких изменений (см. Ниже), все же можно достичь этого результата с помощью Ecto.Changeset.validate_change/3
, и его больше прибитого родного брата Ecto.Changeset.validate_exclusion/4
. В приведенном здесь примере показано, как предотвратить проверку некоторых наборов изменений на основе значений.
Более общий способ заключается в реализации Ecto.Repo.delete/2
(и Ecto.Repo.delete!/2
) обратные вызовы для проверки значений перед делегированием по умолчанию Ecto.Repo.Schema.delete/4
@impl Ecto.Repo
def delete(struct, opts \\ []) do
# check the record and execute the code below
# if and only if the check passed
Ecto.Repo.Schema.delete(
__MODULE__,
get_dynamic_repo(),
struct,
with_default_options(:delete, opts)
)
end
Это все еще очень подвержено ошибкам, потому что можно просто выполнить необработанный запрос через Ecto.Adapters.SQL.query/4
Ecto.Adapters.SQL.query(MyRepo, "DELETE FROM users WHERE email = ", [admin_email])
Кроме того, можно изменить электронное письмо, и в таком случае вы захотите вместо этого защитить UPDATE
.
Тем не менее, единственный правильный способ go состоит в том, чтобы полагаться на БД для отклонения таких удалений. Это можно сделать с помощью TRIGGER
или RULE
в PostgreSQL. Вот пример триггера.
CREATE OR REPLACE FUNCTION prevent_email_hacks()
RETURNS "trigger" AS
'
BEGIN
IF OLD.email = "admin@foo.bar" THEN
RAISE EXCEPTION \'This email is locked\';
END IF;
RETURN NEW;
END;
'
LANGUAGE 'plpgsql' VOLATILE;
CREATE TRIGGER protect_admin
BEFORE INSERT OR UPDATE OR DELETE
ON users
FOR EACH ROW
EXECUTE PROCEDURE prevent_email_hacks();