Подтвердить что ты не робот

Как использовать модуль Repo в файле модели

В моем теге код модели

schema "tags" do
  field :name, :string
  field :parent, :integer # parent tag id
  timestamps
end

def add_error_when_not_exists_tag_id(changeset, params) do
  tags = Repo.all(Tag)
  is_exists_tag_id = Enum.reduce(tags, fn(x, acc) -> acc || (x.id === params.parent) end)
  if is_exists_tag_id, do: changeset, else: add_error(changeset, :parent, "not exists parent!")
end

Выше код вызвал ошибку ниже.

(UndefinedFunctionError) undefined function: Repo.all/1 (module Repo is not available)

Можно ли исправить ошибку?

Модель тега - это тег вложенная.

У тега может быть родительский тег.


Окончательный код приведен ниже. Это хорошо работает.

В модели

def add_error_when_not_exists_tag_id(changeset, params, tags) do
  is_exists_tag_id = Enum.reduce(tags, false, fn(x, acc) -> acc || (Integer.to_string(x.id) === params["parent"]) end)
  if is_exists_tag_id, do: changeset, else: add_error(changeset, :parent, "The tag is not exists.")
end

В контроллере

def create(conn, %{"tag" => tag_params}) do
  changeset = Tag.changeset(%Tag{}, tag_params)
  |> Tag.add_error_when_not_exists_tag_id(tag_params, Repo.all(Tag))
  //
  // ...
4b9b3361

Ответ 1

Вы не можете использовать переменную Repo, поскольку она недоступна в этом модуле. Вам нужно будет сделать так:

alias MyApp.Repo

В контроллерах это обрабатывается для вас в web.ex, который вызывается в вашем модуле с помощью:

use MyApp.Web, :controller

Однако я сильно предлагаю избегать использования Repo в вашей модели. Ваши модели должны быть чистыми, это означает, что они не должны иметь побочных эффектов. Вызов функции в вашей модели должен всегда иметь один и тот же вывод для определенного входа (idempotence).

В этом примере вы можете изменить реализацию функции на:

def add_error_when_not_exists_tag_id(changeset, params, tags) do
  is_exists_tag_id = Enum.reduce(tags, fn(x, acc) -> acc || (x.id === params.parent) end)
  if is_exists_tag_id, do: changeset, else: add_error(changeset, :parent, "not exists parent!")
end

Вы можете вызвать Repo.all в своем контроллере и передать теги в функцию.

Если у вас более сложное поведение, подумайте о создании модуля TagService, который использует эту функцию, а также вызывает Repo.all