使用has_many关联进行身份验证

时间:2016-05-02 13:18:30

标签: elixir phoenix-framework

我正在使用基本的Phoenix应用程序中的身份验证概念。我有一个User has_many emails。用户可以通过输入他/她的电子邮件地址在http://localhost:4000/sessions/new登录。不幸的是,我陷入了困境。我需要在 auth.ex 中做些什么来解决这个问题?

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

2 个答案:

答案 0 :(得分:1)

您需要导入$.ajaxSetup({ cache: false }); 才能使查询生效。

Ecto.Query

另外,请注意内部联接,它假定电子邮件&#39;价值观是独一无二的。

答案 1 :(得分: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功能才能让插件正常工作。