這一章里,我們將添加退出登錄的功能。
先寫測試:
diff --git a/test/controllers/session_controller_test.exs b/test/controllers/session_controller_test.exs
index c5f4616..511d0ab 100644
--- a/test/controllers/session_controller_test.exs
+++ b/test/controllers/session_controller_test.exs
@@ -26,6 +26,8 @@ defmodule TvRecipe.SessionControllerTest do
# 讀取用戶頁,頁面上包含已登錄用戶的用戶名
conn = get conn, Routes.user_path(conn, :show, user)
assert html_response(conn, 200) =~ Map.get(@valid_user_attrs, :username)
+ # 登錄后的頁面顯示“退出”
+ assert html_response(conn, 200) =~ "退出"
end
我們測試用戶登錄后,頁面上是否有“退出”兩字。
當(dāng)然,現(xiàn)在的測試是通不過的:
$ mix test
Compiling 1 file (.ex)
..............................
1) test login user and redirect to home page when data is valid (TvRecipe.SessionControllerTest)
test/controllers/session_controller_test.exs:13
Assertion with =~ failed
code: html_response(conn, 200) =~ "退出"
left: "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\">\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <meta name=\"description\" content=\"\">\n <meta name=\"author\" content=\"\">\n\n <title>Hello TvRecipe!</title>\n <link rel=\"stylesheet\" href=\"/css/app.css\">\n </head>\n\n <body>\n <div class=\"container\">\n <header class=\"header\">\n <nav role=\"navigation\">\n <ul class=\"nav nav-pills pull-right\">\n <li><a href=\"http://www.phoenixframework.org/docs\">Get Started</a></li>\n <li><a href=\"/users/625\">chenxsan</a></li>\n </ul>\n </nav>\n <span class=\"logo\"></span>\n </header>\n\n <p class=\"alert alert-info\" role=\"alert\"></p>\n <p class=\"alert alert-danger\" role=\"alert\"></p>\n\n <main role=\"main\">\n<h2>Show user</h2>\n\n<ul>\n\n <li>\n <strong>Username:</strong>\nchenxsan </li>\n\n <li>\n <strong>Email:</strong>\nchenxsan@gmail.com </li>\n\n <li>\n <strong>Password:</strong>\n </li>\n\n</ul>\n\n<a href=\"/users/625/edit\">Edit</a><a href=\"/users\">Back</a>\n </main>\n\n </div> <!-- /container -->\n <script src=\"/js/app.js\"></script>\n </body>\n</html>\n"
right: "退出"
stacktrace:
test/controllers/session_controller_test.exs:30: (test)
....
Finished in 0.4 seconds
35 tests, 1 failure
打開 app.html.eex
文件,做如下修改:
diff --git a/web/templates/layout/app.html.eex b/web/templates/layout/app.html.eex
index 2d39904..6c87a08 100644
--- a/web/templates/layout/app.html.eex
+++ b/web/templates/layout/app.html.eex
@@ -19,6 +19,7 @@
<li><a href="http://www.phoenixframework.org/docs">Get Started</a></li>
<%= if @current_user do %>
<li><%= link @current_user.username, to: user_path(@conn, :show, @current_user) %></li>
+ <li><%= link "退出", to: Routes.session_path(@conn, :delete, @current_user), method: "delete" %></li>
<% end %>
</ul>
</nav>
現(xiàn)在運行測試:
$ mix test
.............................
1) test creates resource and redirects when data is valid (TvRecipe.UserControllerTest)
test/controllers/user_controller_test.exs:18
** (ArgumentError) No helper clause for TvRecipe.Router.Helpers.session_path/3 defined for action :delete.
The following session_path actions are defined under your router:
* :create
* :new
stacktrace:
(phoenix) lib/phoenix/router/helpers.ex:269: Phoenix.Router.Helpers.raise_route_error/5
(tv_recipe) web/templates/layout/app.html.eex:22: TvRecipe.LayoutView."app.html"/1
(phoenix) lib/phoenix/view.ex:335: Phoenix.View.render_to_iodata/3
(phoenix) lib/phoenix/controller.ex:642: Phoenix.Controller.do_render/4
(tv_recipe) web/controllers/page_controller.ex:1: TvRecipe.PageController.action/2
(tv_recipe) web/controllers/page_controller.ex:1: TvRecipe.PageController.phoenix_controller_pipeline/2
(tv_recipe) lib/tv_recipe/endpoint.ex:1: TvRecipe.Endpoint.instrument/4
(tv_recipe) lib/phoenix/router.ex:261: TvRecipe.Router.dispatch/2
(tv_recipe) web/router.ex:1: TvRecipe.Router.do_call/2
(tv_recipe) lib/tv_recipe/endpoint.ex:1: TvRecipe.Endpoint.phoenix_pipeline/1
(tv_recipe) lib/tv_recipe/endpoint.ex:1: TvRecipe.Endpoint.call/2
(phoenix) lib/phoenix/test/conn_test.ex:224: Phoenix.ConnTest.dispatch/5
test/controllers/user_controller_test.exs:23: (test)
...
2) test login user and redirect to home page when data is valid (TvRecipe.SessionControllerTest)
test/controllers/session_controller_test.exs:13
** (ArgumentError) No helper clause for TvRecipe.Router.Helpers.session_path/3 defined for action :delete.
The following session_path actions are defined under your router:
* :create
* :new
stacktrace:
(phoenix) lib/phoenix/router/helpers.ex:269: Phoenix.Router.Helpers.raise_route_error/5
(tv_recipe) web/templates/layout/app.html.eex:22: TvRecipe.LayoutView."app.html"/1
(phoenix) lib/phoenix/view.ex:335: Phoenix.View.render_to_iodata/3
(phoenix) lib/phoenix/controller.ex:642: Phoenix.Controller.do_render/4
(tv_recipe) web/controllers/page_controller.ex:1: TvRecipe.PageController.action/2
(tv_recipe) web/controllers/page_controller.ex:1: TvRecipe.PageController.phoenix_controller_pipeline/2
(tv_recipe) lib/tv_recipe/endpoint.ex:1: TvRecipe.Endpoint.instrument/4
(tv_recipe) lib/phoenix/router.ex:261: TvRecipe.Router.dispatch/2
(tv_recipe) web/router.ex:1: TvRecipe.Router.do_call/2
(tv_recipe) lib/tv_recipe/endpoint.ex:1: TvRecipe.Endpoint.phoenix_pipeline/1
(tv_recipe) lib/tv_recipe/endpoint.ex:1: TvRecipe.Endpoint.call/2
(phoenix) lib/phoenix/test/conn_test.ex:224: Phoenix.ConnTest.dispatch/5
test/controllers/session_controller_test.exs:24: (test)
.
Finished in 0.5 seconds
35 tests, 2 failures
前一個測試中的錯誤消除了,卻又多了兩個錯誤。這是因為我們還沒有定義 session_controller.ex
文件中的 delete
動作及相應(yīng)路由。
我們希望用戶登錄后點擊“退出”,頁面跳轉(zhuǎn)到主頁,并顯示“退出成功”。
我們的測試這么寫:
diff --git a/test/controllers/session_controller_test.exs b/test/controllers/session_controller_test.exs
index 511d0ab..969662a 100644
--- a/test/controllers/session_controller_test.exs
+++ b/test/controllers/session_controller_test.exs
@@ -50,4 +50,18 @@ defmodule TvRecipe.SessionControllerTest do
assert html_response(conn, 200) =~ "登錄"
end
+ test "logouts user when logout button clicked", %{conn: conn} do
+ # 在數(shù)據(jù)庫中新建一個用戶
+ changeset = User.changeset(%User{}, @valid_user_attrs)
+ user = Repo.insert!(changeset)
+
+ # 登錄該用戶
+ conn = post conn, Routes.session_path(conn, :create), session: Map.delete(@valid_user_attrs, :username)
+
+ # 點擊退出
+ conn = delete conn, Routes.session_path(conn, :delete, user)
+ assert get_flash(conn, :info) == "退出成功"
+ assert redirected_to(conn) == Routes.page_path(conn, :index)
+ end
+
end
接著我們根據(jù)測試中的要求調(diào)整 session_controller.ex
文件及 router.ex
:
diff --git a/web/controllers/session_controller.ex b/web/controllers/session_controller.ex
index b5218f2..2a887ee 100644
--- a/web/controllers/session_controller.ex
+++ b/web/controllers/session_controller.ex
@@ -30,4 +30,11 @@ defmodule TvRecipe.SessionController do
|> render("new.html")
end
end
+
+ def delete(conn, _params) do
+ conn
+ |> delete_session(:user_id)
+ |> put_flash(:info, "退出成功")
+ |> redirect(to: Routes.page_path(conn, :index))
+ end
end
diff --git a/web/router.ex b/web/router.ex
index 1265c86..4c12197 100644
--- a/web/router.ex
+++ b/web/router.ex
@@ -21,6 +21,7 @@ defmodule TvRecipe.Router do
resources "/users", UserController
get "/sessions/new", SessionController, :new
post "/sessions/new", SessionController, :create
+ delete "/sessions/:id", SessionController, :delete
end
# Other scopes may use custom stacks.
運行測試,全部通過。
我們還可以優(yōu)化下 router.ex
文件:
diff --git a/web/router.ex b/web/router.ex
index 4c12197..292aeb8 100644
--- a/web/router.ex
+++ b/web/router.ex
@@ -19,9 +19,7 @@ defmodule TvRecipe.Router do
get "/", PageController, :index
resources "/users", UserController
- get "/sessions/new", SessionController, :new
- post "/sessions/new", SessionController, :create
- delete "/sessions/:id", SessionController, :delete
+ resources "/sessions", SessionController, only: [:new, :create, :delete]
end
# Other scopes may use custom stacks.
更多建議: