2015-09-30 11 views
11

W mojej aplikacji Phoenix Mam modelu użytkownika w następujący sposób:UNIQUE indeksu nie działa w Phoenix aplikacji

defmodule MyApp.User do 
    use MyApp.Web, :model 

    schema "users" do 
    field :username, :string, unique: true 
    field :email, :string, unique: true 
    field :crypted_password, :string 
    field :password, :string, virtual: true 

    timestamps 
    end 

    @required_fields ~w(email password username) 
    @optional_fields ~w() 

    @doc """ 
    Creates a changeset based on the `model` and `params`. 

    If no params are provided, an invalid changeset is returned 
    with no validation performed. 
    """ 
    def changeset(model, params \\ :empty) do 
    model 
    |> cast(params, @required_fields, @optional_fields) 
    |> unique_constraint(:email) 
    |> unique_constraint(:username) 
    |> validate_format(:email, ~r/@/) 
    |> validate_length(:password, min: 5) 
    end 
end 

Mam także następujące migracji:

defmodule MyApp.Repo.Migrations.CreateUser do 
    use Ecto.Migration 

    def change do 
    create table(:users) do 
     add :email, :string 
     add :username, :string 
     add :crypted_password, :string 

     timestamps 
    end 

    create unique_index(:users, [:email]) 
    create unique_index(:users, [:username]) 
    end 
end 

I mam registration_controller_ex jako następująco:

defmodule MyApp.RegistrationController do 
    use MyApp.Web, :controller 
    alias MyApp.User 

    def new(conn, _params) do 
    changeset = User.changeset(%User{}) 
    render conn, changeset: changeset 
    end 

    def create(conn, %{"user" => user_params}) do 
    changeset = User.changeset(%User{}, user_params) 

    if changeset.valid? do 
     user = MyApp.Registration.create(changeset, MyApp.Repo) 
     conn 
     |> put_flash(:info, "Your account was created") 
     |> redirect(to: "/") 
    else 
     conn 
     |> put_flash(:info, "Unable to create account") 
     |> render("new.html", changeset: changeset) 
    end 
    end 
end 

Tak, ze wszystkim, jestem całkiem pewien, że mój username i email pola w User są unikalnymi indeksami. Upewniam się również, że są unikatowe, dzwoniąc pod numer unique_constraint, aby sprawdzić poprawność User.changeset. Jednak, gdy w moim interfejsie utworzę użytkownika z tym samym adresem e-mail i nazwą użytkownika, co wcześniej utworzony, zestaw zmian jest sprawdzany, a użytkownik jest "tworzony". (to nie jest faktycznie tworzone, kiedy zaglądam do bazy danych nic nie jest dodawane)

Otrzymuję następujące informacje na logach mojego serwera, ale mój changeset.valid? jest prawdziwy.

[debug] BEGIN [] OK query=139.3ms queue=8.2ms 
[debug] INSERT INTO "users" ("crypted_password", "email", "inserted_at", "updated_at", "username") VALUES ($1, $2, $3, $4, $5) RETURNING "id" ["$2b$12$MN1YxFUGLMIJYXseZn0sjuuVs9U1jRdYtRr9D8XQsAqdh.D2sRRXa", "[email protected]", {{2015, 9, 30}, {11, 7, 25, 0}}, {{2015, 9, 30}, {11, 7, 25, 0}}, "username"] ERROR query=5.5ms 
[debug] ROLLBACK [] OK query=0.4ms 

Również inne rzeczy, które szukam w mojej funkcji User.changeset (takie jak minimalnej długości hasła i inne rzeczy) Get zgłaszane do użytkownika i działa dobrze. To tylko unikatowe indeksy dla :email i :username, których nie można zgłosić.

Odpowiedz

17

Baza danych zostanie sprawdzona przez unique_constraint, a zatem zostanie wyzwolona tylko po włożeniu rekordu. Wywołanie changeset.valid? nie spowoduje sprawdzenia ograniczeń, a zatem w tym przypadku zwraca wartość true. Trzeba sprawdzić krotki powrotną wkładki Repo i działają na tym takie jak:

def create(conn, %{"user" => user_params}) do 
    changeset = User.changeset(%User{}, user_params) 
    case MyApp.Repo.insert changeset do 
    {:ok, changeset} -> 
     conn 
     |> put_flash(:info, "Your account was created") 
     |> redirect(to: "/")  
    {:error, changeset} -> 
     conn 
     |> put_flash(:info, "Unable to create account") 
     |> render("new.html", changeset: changeset)  
    end 
end 

teraz swój changeset.errors wzbogacona jest i powinna być w stanie sprowadzić błąd z changeset.errors[:email]

+0

to nie działa. Mam problem: registration_controller.ex: 15: function changeset/0 undefined –

+0

Dla potomności powyższy wiersz powinien zostać nieco zmieniony: changset = User.changeset (% User {}, user_params) – pip