В чем разница между схемой и моделью? - PullRequest
1 голос
/ 29 апреля 2020

Я только начал есть Феникс, и я не очень хорошо понял одну вещь, я искал и увидел, что схемы - это структура базы данных, а модели имеют высокий уровень и обрабатывают логи c, но в Фениксе мы имеем только схемы, так, например, если бы я сделал пароль ha sh, он должен быть в схеме пользователя? Или я должен положить его в контроллер?

1 Ответ

1 голос
/ 29 апреля 2020

Вообще говоря, вы хотите, чтобы ваши приложения MVC имели "тонкие контроллеры" - эта рекомендация применима для нескольких языков. В некоторых языках / средах это очень важно, потому что тестирование контроллеров может быть довольно сложным. Хотя тестирование контроллеров относительно просто на функциональном языке, таком как Elixir, и хорошо структурированной среде, такой как Phoenix, вы все равно должны поддерживать свои контроллеры как можно более компактными. Проще говоря, контроллеры должны подключить сервисный модуль (часто называемый «контекст» в Фениксе) с представлением. Обычно в них не так уж много логи c.

Термины «схемы» могут быть запутанными - потратьте немного времени, чтобы понять, что разные базы данных используют разные термины для обозначения (более или менее) ) одинаковые компоненты. Например, «база данных» в MySQL называется «схемой» в Oracle или Postgres. В Ecto "схема" аналогична "модели" ORM во многих других средах: схема Ecto представляет в коде "форму" определенной таблицы базы данных c (поэтому, возможно, именно поэтому они используют один и тот же термин).

Однако в вашем случае что-то вроде вычисляемого поля пароля ha sh должно находиться в том же модуле, что и схема Ecto. (Да, Ecto делает несколько макрочасов c, когда определяет форму таблицы в коде, но это все еще модуль, и это рекомендуемое место для размещения changeset функций, которые имеют дело с проверкой и изменением данных, прежде чем они попадут в база данных).

Если вам когда-нибудь станет интересно, где некоторые функции должны go, спросите себя, куда бы вы поместили код, если пользовательский ввод исходил из CLI, а не из Интернета. Если бы у вас была задача смешивания CLI, которая создала пользователя с паролем, вы бы использовали веб-контроллер? Нет, вы бы не стали: контроллер - это просто go -потерь, который соединяет веб-запрос / ответ с базовой моделью / схемой. Вы не захотите продублировать код, который рассчитал пароль ha sh только потому, что вы хотели создать его для скрипта CLI, чтобы у вас было логическое место для его размещения: в схеме.

Наборы изменений Ecto позволяют изменять данные на пути к базе данных. Вы можете услышать, что это называется «мутацией» в некоторых системах или «вычисляемым полем».

Вот пример, который вычисляет поле «create_at» (да, вы можете сделать это в базе данных, но это полезный пример того, как сделать вычисляемое поле в коде):

  @doc false
  def changeset(user, attrs) do
    user
    |> cast(attrs, [:username,:email])
    |> validate_required([:username,:email])
    |> add_created_at()
    |> unique_constraint(:username)
    |> unique_constraint(:email)
  end

  defp add_created_at(changeset) do
    case changeset do
      %Ecto.Changeset{
        valid?: true,
        changes: _user
      } ->
        put_change(
          changeset,
          :created_at,
          DateTime.utc_now
          |> DateTime.truncate(:second)
        )
      _ ->
        changeset
    end
  end

А вот пример расчета пароля ha sh для хранения в вашей базе данных - с использованием пакета Argon2. Это также добавляет поле, которое идентифицирует, какой алгоритм использовался, чтобы иметь sh пароль (в виде строки, полезной для справки):

  def changeset(user, attrs) do
    user
    |> cast(attrs, [:username, :password])
    |> validate_required([:username, :password])
    |> validate_length(:password, min: 8, max: 100)
    |> unique_constraint(:username)
    |> put_password_hash()
  end


  defp put_password_hash(changeset) do
    case changeset do
      %Ecto.Changeset{
        valid?: true,
        changes: %{
          password: plain_text
        }
      } ->
        put_change(changeset, :password_hash, Argon2.hash_pwd_salt(plain_text))
        |> put_change(:algorithm, "argon2")

      _ ->
        changeset
    end
  end

Надеюсь, что поможет.

...