Набор учетных данных не вставлен в базу данных - PullRequest
0 голосов
/ 22 июня 2019

Когда я создаю нового пользователя, я прохожу следующий процесс,

accounts.ex

def register_user(attrs \\ %{}) do
    %User{}
    |> User.registration_changeset(attrs)
    |> Repo.insert()
end

user.ex

def changeset(user, attrs) do
    user
    |> cast(attrs, [:name, :username])
    |> validate_required([:name, :username])
    |> validate_length(:username, min: 1, max: 20)
    |> unique_constraint(:username)
end

def registration_changeset(user, params) do
    user
    |> changeset(params)
    |> Ecto.Changeset.cast_assoc(:credential, with: &Credential.changeset/2)
end

credential.ex

def changeset(credential, attrs) do
    credential
    |> cast(attrs, [:email, :password])
    |> validate_required([:email, :password])
    |> validate_length(:password, min: 6, max: 100)
    |> unique_constraint(:email)
    |> put_hash()
end

defp put_hash(changeset) do
    case changeset do
      %Ecto.Changeset{valid?: true, changes: %{password: pass}} ->
        put_change(changeset, :password_hash, Bcrypt.hash_pwd_salt(pass))
      _ ->
        changeset
    end
end

При тестировании я получаю следующее:

iex(0)> Accounts.register_user(%{name: "Test", username: "test", email: "test@here.com", password: "12345678"})
[debug] QUERY OK db=17.2ms queue=1.7ms

При попытке просмотра пользователя я заметил, что таблица Credentials пуста,

iex(1)> Repo.all User
[debug] QUERY OK source="users" db=1.5ms decode=0.1ms queue=0.2ms
[    
  %App.Accounts.User{
    __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
    credential: #Ecto.Association.NotLoaded<association :credential is not loaded>,
    id: 1,
    inserted_at: ~N[2019-06-21 16:39:46],
...
]

iex(2)> Repo.all Credential
[debug] QUERY OK source="credentials" db=5.5ms queue=0.1ms
[]

Что я здесь не так делаю?

Ответы [ 2 ]

3 голосов
/ 24 июня 2019

cast_assoc требуется еще один уровень вложенности.

В вашем примере cast_assoc(:credential, ...) пытается найти ключ credentials в ваших параметрах, а в параметрах в поле этот ключ будет пытаться разыграть как Credential changeset.

Вот пример из документов :

%{"name" => "john doe", "addresses" => [
  %{"street" => "somewhere", "country" => "brazil", "id" => 1},
  %{"street" => "elsewhere", "country" => "poland"},
]}

который превращается в:

User
|> Repo.get!(id)
|> Repo.preload(:addresses) # Only required when updating data
|> Ecto.Changeset.cast(params, [])
|> Ecto.Changeset.cast_assoc(:addresses, with: &MyApp.Address.changeset/2)

Как видите, входная структура данных JSON имеет ключ "addresses", который затем преобразуется в :addresses

Итак, ваши данные должны иметь следующую структуру:

%{
  name: "Test", 
  username: "test", 
  credential: %{
    email: "test@here.com", 
    password: "12345678"
  }
}

Конечно, это не то, что вам нравится в процессе регистрации!

Итак, у вас есть два решения:

  • Отбросьте весь этот мандат сотрудников и сохраните его простым с внутренней регистрацией изменений.

  • Создайте ассоциацию вручную - с помощью build_assoc или put_assoc

0 голосов
/ 26 июня 2019

Включите ваши адреса электронной почты и пароль с помощью функции inputs_for/4.

<%= inputs_for f, :credential, fn cf -> %>
   <%= email_input cf, :email %>
   <%= password_input cf, :password %>
<% end %>

Это предварительно загрузит учетные данные для вас. Вот ссылка

...