2016-05-02 12 views
0

Ich arbeite durch Authentifizierungskonzepte in einer einfachen Phoenix App. Ich habe eine User wer has_manyemails. Ein Benutzer kann sich unter der Nummer http://localhost:4000/sessions/new anmelden, indem er seine E-Mail-Adresse eingibt. Leider stecke ich an diesem Punkt fest. Was muss ich in auth.ex tun, um das zu beheben?Authentifizierung mit has_many association

mix phoenix.new my_app --database mysql 
cd my_app 
mix phoenix.gen.html User users name:string 
mix phoenix.gen.html Email emails value:string user_id:references:users 
mix ecto.create 
mix ecto.migrate 

web/router.ex

[...] 
scope "/", MyApp do 
    pipe_through :browser # Use the default browser stack 

    get "/", PageController, :index 
    resources "/users", UserController 
    resources "/emails", EmailController 
    resources "/sessions", SessionController, only: [:new, :create, :delete] 
end 
[...] 

Web/Modelle/user.ex

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

    schema "users" do 
    field :name, :string 
    has_many :emails, MyApp.Email 

    timestamps 
    end 

    @required_fields ~w(name) 
    @optional_fields ~w() 

    def changeset(model, params \\ :empty) do 
    model 
    |> cast(params, @required_fields, @optional_fields) 
    end 
end 

Web/Modelle/email.ex

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

    schema "emails" do 
    field :value, :string 
    belongs_to :user, MyApp.User 

    timestamps 
    end 

    @required_fields ~w(value user_id) 
    @optional_fields ~w() 

    def changeset(model, params \\ :empty) do 
    model 
    |> cast(params, @required_fields, @optional_fields) 
    end 
end 

web/views/session_view.ex

defmodule MyApp.SessionView do 
    use MyApp.Web, :view 
end 

web/templates/session/new.html.eex

<h1>Login</h1> 

<%= form_for @conn, session_path(@conn, :create), [as: :session], fn f -> %> 
    <div class="form-group"> 
    <%= text_input f, :email, placeholder: "email" %> 
    </div> 
    <%= submit "Log in" %> 
<% end %> 

web/controllers/session_controller.ex

defmodule MyApp.SessionController do 
    use MyApp.Web, :controller 

    def new(conn, _) do 
    render conn, "new.html" 
    end 

    def create(conn, %{"session" => %{"email" => email}}) do 
    case MyApp.Auth.login_by_email(conn, email, repo: Repo) do 
     {:ok, conn} -> 
     conn 
     |> put_flash(:info, "Welcome!") 
     |> redirect(to: page_path(conn, :index)) 
     {:error, _reason, conn} -> 
     conn 
     |> put_flash(:error, "Invalid email") 
     |> render("new.html") 
    end 
    end 
end 

web/controllers/auth.ex

defmodule MyApp.Auth do 
    import Plug.Conn 
    alias MyApp.User 

    def init(opts) do 
    Keyword.fetch!(opts, :repo) 
    end 

    def login_by_email(conn, email, _opts) do 
    # What code would fix this? 
    # 
    user = repo.get!(User, email) 
    conn 
    |> assign(:current_user, user) 
    |> put_session(:user_id, user.id) 
    |> configure_session(renew: true) 
    end 
end 
+0

Können Sie mehr über das Problem beschreiben? Können Sie einen Nutzer nicht anhand einer E-Mail finden? Oder ist es etwas anderes? – vikram7

+0

Ich kann den Benutzer anhand einer E-Mail nicht finden. – wintermeyer

Antwort

1

Sie müssen Ecto.Query importieren, damit die Abfrage funktioniert.

import Ecto.Query 

def login_by_email(conn, email, _opts) do 
    user = 
    MyApp.User 
    |> join(:inner, [u], e in assoc(u, :emails)) 
    |> where([u, e], e.value == ^email) 
    |> MyApp.Repo.one!()  

    conn 
    |> assign(:current_user, user) 
    |> put_session(:user_id, user.id) 
    |> configure_session(renew: true) 

end 

Beachten Sie auch die innere Verknüpfung, die davon ausgeht, dass die Werte der E-Mails eindeutig sind.

0

können Sie nur die E-Mail abfragen und den Benutzer vorzuladen.

email_with_user = 
    repo.one(from e in Email, 
      join: u in assoc(e, :user), 
      where: e.value == ^email) 
user = email_with_user.user 

Auch sagt die plug specification, dass es init und call Funktion für einen Stecker zu arbeiten sein muß.

+0

Ich bekomme einen 'can not use^E-Mail außerhalb von Match-Klauseln' Fehler damit. – wintermeyer

+0

@wintermeyer versuchen, Ecto.Query zu importieren (oder nur es ist 'von' Funktion) – JustMichael

Verwandte Themen