2016-05-02 9 views
0

私は基本的なPhoenixアプリケーションの認証コンセプトを使って作業しています。私はUser who has_manyemailsです。ユーザーは、自分の電子メールアドレスを入力してhttp://localhost:4000/sessions/newにログインすることができます。残念ながら私はこの時点で立ち往生しています。これを修正するには、auth.exで何をする必要がありますか?has_manyアソシエーションを使用した認証

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 

ウェブ/ 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 
[...] 

ウェブ/モデル/ 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 

ウェブ/モデル/ 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 

ウェブ/ビュー/ session_view.ex

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

ウェブ/テンプレート/セッション/ 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 %> 

ウェブ/コントローラ/ 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 

ウェブ/コントローラ/ 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

問題の詳細を説明できますか?あなたは電子メールに基づいてユーザーを見つけることができませんか?それとも別のことですか? – vikram7

+0

電子メールに基づいてユーザーを見つけることができません。 – wintermeyer

答えて

1

クエリが機能するには、Ecto.Queryをインポートする必要があります。

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 

また、電子メールの値が一意であることを前提とする内部結合に注目してください。

0

あなただけの電子メールを照会し、ユーザーをプリロードすることができます。

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

また、plug specificationが動作するプラグ用initcall機能がなければならないと述べています。

+0

私は 'それ以外では^電子メールを使用できません。 – wintermeyer

+0

@wintermeyer Ecto.Queryをインポートしようとする(または、それが 'from'関数だけである) – JustMichael

関連する問題