I'm working through authentication concepts in a basic Phoenix app. I have a User
who has_many
emails
. A user can login at http://localhost:4000/sessions/new
by entering his/her e-mail address. Unfortunately I'm stuck at this point. What do I have to do in auth.ex to fix this?
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/models/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/models/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