Как использовать модуль 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))
  //
  // ...

1 ответ

Решение

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

alias MyApp.Repo

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

use MyApp.Web, :controller

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

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

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

Другие вопросы по тегам