
翻蚳è
ããïŒã
ãšãªã¯ãµãŒãšãã§ããã¯ã¹ã¯ãææ°ã®ãŠã§ãéçºãã©ãã«é²ãã§ãããã®è¯ãäŸã§ãã ãã§ã«ãããã®ããŒã«ã¯ãWebã¢ããªã±ãŒã·ã§ã³ã®ãªã¢ã«ã¿ã€ã ãã¯ãããžãŒãžã®è³ªã®é«ãã¢ã¯ã»ã¹ãæäŸããŸãã 察話æ§ãåäžãããµã€ãããã«ããŠãŒã¶ãŒãã©ãŠã¶ãŒã²ãŒã ããã€ã¯ããµãŒãã¹ã¯ããããã®æè¡ãããŸãæ©èœããåéã§ãã 以äžã¯ãPhoenixãã¬ãŒã ã¯ãŒã¯ã§ã®éçºã®è©³çްãªåŽé¢ã説æããäžé£ã®11ã®èšäºã®ç¿»èš³ã§ããããã°ãšã³ãžã³ã®ãããªäºçްãªããšã®ããã«æããŸãã æ¥ãã§ã€ãŸãããªãã§ãã ãããç¹ã«èšäºããšãªã¯ãµãŒã«æ³šæãæããã圌ã®ãã©ãã¯ãŒã«ãªãããã«ä¿ããå Žåãããã¯æ¬åœã«é¢çœãã§ããã ãã
çŸæç¹ã§ã¯ãã¢ããªã±ãŒã·ã§ã³ã¯ä»¥äžã«åºã¥ããŠããŸãã
- ãšãªã¯ãµãŒ ïŒv1.3.1
- ãã§ããã¯ã¹ ïŒv1.2.0
- EctoïŒv2.0.2
- ã³ã¡ãã³ ïŒv2.5.2
ãã§ããã¯ã¹ã®ã€ã³ã¹ããŒã«
Phoenixã®æé©ãªã€ã³ã¹ããŒã«æé ã¯
ãå
¬åŒWebãµã€ãã«ãããŸãã
ã¹ããã1.æçš¿ã远å ãã
mixã¿ã¹ã¯ãèµ·åããŠã
pxblogãšããæ°ãããããžã§ã¯ããäœæããããšããå§ããŸãããã ãããè¡ãã«ã¯ãã³ãã³ã
`mix phoenix.new [project] [command]`ãå®è¡ããŸãã ããã©ã«ãã®èšå®ãé©åã§ããããããã¹ãŠã®è³ªåã«è¯å®çã«çããŸãã
mix phoenix.new pxblog
çµè«ïŒ
* creating pxblog/config/config.exs ... Fetch and install dependencies? [Yn] y * running mix deps.get * running npm install && node node_modules/brunch/bin/brunch build We are all set! Run your Phoenix application: $ cd pxblog $ mix phoenix.server You can also run your app inside IEx (Interactive Elixir) as: $ iex -S mix phoenix.server Before moving on, configure your database in config/dev.exs and run: $ mix ecto.create
ãããžã§ã¯ãã®äœæãå®äºãããšããå€ãã®æ
å ±ãšãæºåäœæ¥ã®ããŒã ã衚瀺ãããã¯ãã§ãã ãããã1ã€ãã€å®è¡ããŸãã
PostgresããŒã¿ããŒã¹ãäœæããŠããªãå ŽåããŸãã¯ããŒã¿ããŒã¹ãåäœããããã«ã¢ããªã±ãŒã·ã§ã³ãèšå®ãããŠããªãå Žåã
`mix ecto.create`ã³ãã³ãã¯ãšã©ãŒ
ãã¹ããŒããŸãã ä¿®æ£ããã«ã¯ã
config / dev.exsãã¡ã€ã«ãéããããŒã¿ããŒã¹ãäœæããæš©éãæã€ããŒã«ã®ãŠãŒã¶ãŒåãšãã¹ã¯ãŒãã倿Žããã ãã§ãïŒ
ãã¹ãŠãæ©èœãããããµãŒããŒãèµ·åããŠããã¹ãŠãæ£åžžã§ããããšã確èªããŸãããã
$ iex -S mix phoenix.server
ãããè¡ãã«ã¯ãã¢ãã¬ã¹
httpïŒ// localhostïŒ4000 /ã«ç§»åã ãã
Welcome to PhoenixïŒããåç
§ããŠãã ãã
ã ã è¯ãåºç€ãæŽããŸããã ããã°ãšã³ãžã³ããŸã ããã®ã§ãæçš¿ãæäœããããã®ã¡ã€ã³ã®è¶³å Žã远å ããŸãããã
ãã§ããã¯ã¹ã®çµã¿èŸŒã¿ãžã§ãã¬ãŒã¿ãŒã䜿çšããŠã
Postã¢ãžã¥ãŒã«ã®CRUDæäœãåŠçããããã®å€éšã¢ãã«ãç§»è¡ãããã³ã€ã³ã¿ãŒãã§ã€ã¹ãäœæããŸãã çŸæç¹ã§ã¯ããã¯
éåžžã«åçŽãªãšã³ãžã³ã§ãããããã¿ã€ãã«ãšã¡ãã»ãŒãžã«éå®ããŠããŸãã ã¿ã€ãã«ã¯æååã«ãªããã¡ãã»ãŒãžã¯ããã¹ãã«ãªããŸãã ãã¹ãŠãäœæããããŒã ã¯éåžžã«åçŽã§ãã
$ mix phoenix.gen.html Post posts title:string body:text
çµè«ïŒ
* creating web/controllers/post_controller.ex ... Add the resource to your browser scope in web/router.ex: resources "/posts", PostController Remember to update your repository by running migrations: $ mix ecto.migrate
ãšã©ãŒãçºçããŸãïŒ ãããä¿®æ£ããåæã«ãã©ãŠã¶ããæçš¿ã€ã³ã¿ãŒãã§ã€ã¹ã«ã¢ã¯ã»ã¹ã§ããããã«ããã«ã¯ã
web / router.exãã¡ã€ã«ãéããŠã次ã®è¡ãã«ãŒãã¹ã³ãŒãã«è¿œå ããŸãã
resources "/posts", PostController
ããã§ã³ãã³ããå床å®è¡ããç§»è¡ãæåããããšã確èªã§ããŸãã
$ mix ecto.migrate
çµè«ïŒ
Compiling 9 files (.ex) Generated pxblog app 15:52:20.004 [info] == Running Pxblog.Repo.Migrations.CreatePost.change/0 forward 15:52:20.004 [info] create table posts 15:52:20.019 [info] == Migrated in 0.0s
ãããŠæåŸã«ããµãŒããŒãåèµ·åãã
httpïŒ// localhostïŒ4000 / postsããŒãžã«ç§»åããŸããããã§ã
ãªã¹ãã®æçš¿ã®èŠåºããš
æçš¿ã®
ãªã¹ãã衚瀺ãããŸãã
å°ãæãå ããŠãæ°ããæçš¿ã远å ãç·šéãåé€ããæ©äŒãåŸãŸããã ãã®ãããªå°ããªäœæ¥ã«ã¯ããªã
ã¯ãŒã«ã§ãïŒ
ã¹ããã1Bã æçš¿ã®ãã¹ããæžã
è¶³å Žã§äœæ¥ããåã³ã®1ã€ã¯ãæåããäžé£ã®åºæ¬çãªãã¹ããååŸã§ããããšã§ãã ç¹ã«ãã¢ããªã±ãŒã·ã§ã³èªäœã®ã³ãŒãã«é倧ãªå€æŽãå ãããŸã§ããããã倿Žããå¿
èŠãããããŸããã æ¬¡ã«ãäœæããããã¹ããèŠãŠãç¬èªã®ãã¹ãã®æžãæ¹ãããããçè§£ããŸãããã
æåã«ããã¡ã€ã«
test / models / post_test.exsãéããŠãå
容ãèŠãŠãã ããïŒ
defmodule Pxblog.PostTest do use Pxblog.ModelCase alias Pxblog.Post @valid_attrs %{body: "some content", title: "some content"} @invalid_attrs %{} test "changeset with valid attributes" do changeset = Post.changeset(%Post{}, @valid_attrs) assert changeset.valid? end test "changeset with invalid attributes" do changeset = Post.changeset(%Post{}, @invalid_attrs) refute changeset.valid? end end
ããã§äœãèµ·ãã£ãŠããã®ããçè§£ããããã«ããã®ã³ãŒããéšåçã«åè§£ããŠã¿ãŸãããã
defmodule Pxblog.PostTest do
æããã«ãã¢ããªã±ãŒã·ã§ã³ã®åå空éã«ãã¹ãã¢ãžã¥ãŒã«ãå®çŸ©ããå¿
èŠããããŸãã
Pxblog.ModelCaseã䜿çšããŸã
次ã«ããã®ã¢ãžã¥ãŒã«ã«ã
ModelCaseãã¯ã
ã»ããã§æäŸããã颿°ãšDSLã䜿çšããããã«æç€ºããŸãã
ãšã€ãªã¢ã¹Pxblog.Post
次ã«ããã¹ããã¢ãã«ã«çŽæ¥ã¢ã¯ã»ã¹ã§ããããšã確èªããŸãã
@ valid_attrsïŒ
{bodyïŒâ some contentâãtitleïŒâ some contentâ}
ãªããžã§ã³ ïŒ
changeset ïŒãæ£åžžã«äœæã§ããããã«ããäž»ãªæå¹ãªå±æ§ãèšå®ããŸãã æå¹ãªã¢ãã«ãäœæãããã³ã«ãã«ã§ããã¢ãžã¥ãŒã«ã¬ãã«ã®å€æ°ã§ãã
@ invalid_attrsïŒ
{}
äžèšãšåãã§ãããç¡å¹ãªå±æ§ã®ã»ãããäœæããŸãã
ãæå¹ãªå±æ§ãæã€ãã§ã³ãžã»ãããããã¹ããã
changeset = Post.changesetïŒïŒ
Post {}ã@ valid_attrsïŒ
changeset.validãã¢ãµãŒãããŸããïŒ
çµãã
ããã§ã
ãã¹ã颿°ã䜿çšããŠãã¹ããçŽæ¥äœæããæåååãä»ããŸãã 颿°ã®æ¬äœå
ã§ãæåã«
Postã¢ãã«ãããªããžã§ã³ãäœæããŸãïŒç©ºã®æ§é ãšæå¹ãªãã©ã¡ãŒã¿ãŒã®ãªã¹ããæž¡ããŸãïŒã 次ã«ã
ã¢ãµãŒã颿°ã䜿çšããŠããªããžã§ã³ã®æå¹æ§ãæ€èšŒããŸãã ããã¯ããŸãã«
@valid_attrs倿°ãå¿
èŠãªãã®
ã§ã ã
ãç¡å¹ãªå±æ§ãæã€å€æŽã»ãããããã¹ããã
changeset = Post.changesetïŒïŒ
Post {}ã@ invalid_attrsïŒ
changeset.validã«åè«ããŸããïŒ
çµãã
æåŸã«ãç¡å¹ãªãã©ã¡ãŒã¿ãŒã䜿çšããŠãªããžã§ã³ã®äœæã確èªãããªããžã§ã³ãæå¹ã§ããããšã
ã䞻匵ããã代ããã«ãé
åè«æäœãå®è¡ããŸãã
ããã¯ãã¢ãã«ãã¹ãã®äœææ¹æ³ã®éåžžã«è¯ãäŸã§ãã ããã§ã¯ãã³ã³ãããŒã©ãŒã®ãã¹ããèŠãŠã¿ãŸãããã ãããèŠããšã次ã®ãããªãã®ãèŠããã¯ãã§ãã
defmodule Pxblog.PostControllerTest do use Pxblog.ConnCase alias Pxblog.Post @valid_attrs %{body: "some content", title: "some content"} @invalid_attrs %{} ... end
Pxblog.ConnCaseã䜿çšããŠãç¹å¥ãªã³ã³ãããŒã©ãŒã¬ãã«ã®DSLãååŸããŸãã æ®ãã®è¡ã¯æ¢ã«ããªãã¿ã®ã¯ãã§ãã
æåã®ãã¹ããèŠãŠã¿ãŸãããïŒ
test "lists all entries on index", %{conn: conn} do conn = get conn, post_path(conn, :index) assert html_response(conn, 200) =~ "Listing posts" end
ããã§å€æ°
connããã£ããã£ããŸããããã¯
ConnCaseã®
ãã¥ãŒããŒãä»ããŠéä¿¡ããå¿
èŠããããŸãã ããã«ã€ããŠã¯åŸã§èª¬æããŸãã æ¬¡ã®ã¹ãããã§ã¯ãé©åãªHTTPã¡ãœããã§åãååã®é¢æ°ã䜿çšããŠãç®çã®ãã¹ã«æ²¿ã£ãŠèŠæ±ãè¡ããŸãïŒã¢ã¯ã·ã§ã³ã«å¯Ÿãã
GETèŠæ± ïŒãã®å Žåã¯
ã€ã³ããã¯ã¹ ïŒã 次ã«ããã®ã¢ã¯ã·ã§ã³ã®å¿çãã¹ããŒã¿ã¹
200ïŒãOKãïŒã® HTMLãè¿ãããã¬ãŒãº
Listing postsãå«ãŸããŠããããšã確èªããŸãã
test "renders form for new resources", %{conn: conn} do conn = get conn, post_path(conn, :new) assert html_response(conn, 200) =~ "New post" end
次ã®ãã¹ãã¯åºæ¬çã«åãã§ã
æ°ããã¢ã¯ã·ã§ã³ã®ã¿ãæ¢ã«ãã¹ããããŠããŸãã ãã¹ãŠãã·ã³ãã«ã§ãã
test "creates resource and redirects when data is valid", %{conn: conn} do conn = post conn, post_path(conn, :create), post: @valid_attrs assert redirected_to(conn) == post_path(conn, :index) assert Repo.get_by(Post, @valid_attrs) end
ãããŠãããã§äœãæ°ããããšãããŠããŸãã æåã«ãæå¹ãªãã©ã¡ãŒã¿ãŒã®ãªã¹ããå«ãPOSTãªã¯ãšã¹ãã
post_pathã«éä¿¡ããŸãã æçš¿ã®ãªã¹ãã«ãªãã€ã¬ã¯ããããäºå®ã§ãïŒaction
ïŒindex ïŒã
redirected_to颿°ã¯ããªãã€ã¬ã¯ããçºçããå Žæãç¥ãå¿
èŠããããããæ¥ç¶ãªããžã§ã¯ããåŒæ°ãšããŠåãåããŸãã
æåŸã«ããããã®æå¹ãªãã©ã¡ãŒã¿ãŒã«ãã£ãŠè¡šããããªããžã§ã¯ããããŒã¿ããŒã¹ã«æ£åžžã«è¿œå ããããšäž»åŒµããŸãã ãã®ãã§ãã¯ã¯ã
Ecto Repoãªããžããªãžã®ãªã¯ãšã¹ããéããŠè¡ããã
@ valid_attrsãã©ã¡ãŒã¿ãŒã«äžèŽãã
Postã¢ãã«ãèŠã€ããŸãã
test "does not create resource and renders errors when data is invalid", %{conn: conn} do conn = post conn, post_path(conn, :create), post: @invalid_attrs assert html_response(conn, 200) =~ "New post" end
ããäžåºŠãæçš¿ã®äœæã詊ã¿ãŸããããã©ã¡ãŒã¿ãŒ
@invalid_attrsã®ç¡å¹ãªãªã¹ãã䜿çšããŠãæçš¿ãäœæããããã®ãã©ãŒã ãåã³è¡šç€ºãããããšã確èªããŸãã
test "shows chosen resource", %{conn: conn} do post = Repo.insert! %Post{} conn = get conn, post_path(conn, :show, post) assert html_response(conn, 200) =~ "Show post" end
showã¢ã¯ã·ã§ã³ããã¹ãããã«ã¯ã
Postã¢ãã«ãäœæããå¿
èŠããããŸããããã䜿çšããŠäœæ¥ããŸãã æ¬¡ã«ã
post_pathãã«ããŒã䜿çšããŠ
get颿°ãåŒã³åºãã察å¿ãããªãœãŒã¹ãè¿ãããããšã確èªããŸãã
次ã®ããã«ãååšããªããªãœãŒã¹ãžã®ãã¹ãèŠæ±ããããšãã§ããŸãã
test "renders page not found when id is nonexistent", %{conn: conn} do assert_error_sent 404, fn -> get conn, post_path(conn, :show, -1) end end
å¥ã®ãã¹ãèšé²ãã³ãã¬ãŒãã䜿çšããŸãããå®éã«ã¯éåžžã«ç°¡åã«çè§£ã§ããŸãã ååšããªããªãœãŒã¹ãžã®ãªã¯ãšã¹ãããšã©ãŒ404ã«ã€ãªãããšããæåŸ
ã«ã€ããŠèª¬æããŸããããã§ãå®è¡æã«ãã®ãšã©ãŒãè¿ãã³ãŒããå«ãå¿å颿°ãæž¡ããŸãã ãã¹ãŠãã·ã³ãã«ã§ãïŒ
æ®ãã®ãã¹ãã¯ãæ®ãã®ãã¹ã«å¯ŸããŠã®ã¿äžèšãç¹°ãè¿ããŸãã ããããåé€ã®è©³çްã«ã€ããŠã¯æ¬¡ã®ãšããã§ãã
test "deletes chosen resource", %{conn: conn} do post = Repo.insert! %Post{} conn = delete conn, post_path(conn, :delete, post) assert redirected_to(conn) == post_path(conn, :index) refute Repo.get(Post, post.id) end
äžè¬ã«ãHTTP
åé€ã¡ãœããã䜿çšããããšãé€ããŠããã¹ãŠãé¡äŒŒããŠããŸãã åé€ããŒãžããæçš¿ã®ãªã¹ãã«ãªãã€ã¬ã¯ãããå¿
èŠããããš
䞻匵ããŠããŸãã ããã§ãæ°ããæ©èœã䜿çšããŸã
-refute颿°ã䜿çšããŠ
Postãªããžã§ã¯ãã®ååšã
ãæåŠãããŸãã
ã¹ããã2.ãŠãŒã¶ãŒã远å ãã
ãŠãŒã¶ãŒã¢ãã«ãäœæããã«ã¯ãä»ã®åã远å ããããšãé€ããŠãæçš¿ã®ã¢ãã«ãäœæãããšããšã»ãŒåãæé ãå®è¡ããŸãã éå§ããã«ã¯ã次ãå®è¡ããŸãã
$ mix phoenix.gen.html User users username:string email:string password_digest:string
çµè«ïŒ
* creating web/controllers/user_controller.ex ... Add the resource to your browser scope in web/router.ex: resources "/users", UserController Remember to update your repository by running migrations: $ mix ecto.migrate
次ã«ã
web / router.exãã¡ã€ã«ãéãã以åãšåãã¹ã³ãŒãã«æ¬¡ã®è¡ã远å ããŸãã
resources "/users", UserController
ããã®æ§æã¯ãæåã®åŒæ°ãURLã§ã2çªç®ãã³ã³ãããŒã©ãŒã¯ã©ã¹ã®ååã§ããæšæºãªãœãŒã¹ãã¹ãå®çŸ©ããŸãã ããããïŒ
$ mix ecto.migrate
çµè«ïŒ
Compiling 11 files (.ex) Generated pxblog app 16:02:03.987 [info] == Running Pxblog.Repo.Migrations.CreateUser.change/0 forward 16:02:03.987 [info] create table users 16:02:03.996 [info] == Migrated in 0.0s
æåŸã«ããµãŒããŒãåèµ·åãã
httpïŒ// localhostïŒ4000 / usersã確èªã
ãŸã ã æçš¿ã«å ããŠããŠãŒã¶ãŒã远å ã§ããããã«ãªããŸããïŒ
æ®å¿µãªãããããã¯ãŸã ããŸãæçšãªããã°ã§ã¯ãããŸããã æçµçã«ã¯ããŠãŒã¶ãŒãäœæã§ããŸãïŒ
æ®å¿µãªããã誰ã§ãäœæ
ã§ããããã«ãªã£ãŠããŸã ïŒãããã°ã€ã³ããã§ããŸããã ããã«ããã¹ã¯ãŒããã€ãžã§ã¹ãã¯æå·åã¢ã«ãŽãªãºã ã䜿çšããŸããã ãŠãŒã¶ãŒãå
¥åããããã¹ããæãã«ä¿æããŸãïŒ ãŸã£ããã¯ãŒã«ã§ã¯ãããŸããïŒ
ãã®ç»é¢ããã£ãšç»é²ã®ãããªãã¥ãŒã«ããŸãããã
ãŠãŒã¶ãŒãã¹ãã¯æçš¿çšã«èªåçæããããã®ãšãŸã£ããåãããã«èŠããã®ã§ãããžãã¯ã倿Žãå§ãããŸã§ãã®ãŸãŸã«ããŠãããŸãïŒ
ãããŠä»ãããããè¡ããŸãïŒ ïŒã
ã¹ããã3.ãã¹ã¯ãŒãèªäœã®ä»£ããã«ãã¹ã¯ãŒãããã·ã¥ãä¿åãã
ã¢ãã¬ã¹
/ users / newãéããšã
Username ã
Email ã
PasswordDigestã® 3ã€ã®ãã£ãŒã«ãã衚瀺ãããŸãã ããããä»ã®ãµã€ãã§ç»é²ãããšãã¯ããã¹ã¯ãŒããã€ãžã§ã¹ãã§ã¯ãªãããã¹ã¯ãŒãèªäœãšãã®ç¢ºèªãå
¥åããããã«æ±ããããŸãïŒ ã©ãããã°ä¿®æ£ã§ããŸããïŒ
web / templates / user / form.html.eexãã¡ã€ã«ã§ ãæ¬¡ã®è¡ãåé€ããŸãã
<div class="form-group"> <%= label f, :password_digest, class: "control-label" %> <%= text_input f, :password_digest, class: "form-control" %> <%= error_tag f, :password_digest %> </div>
ãããŠã代ããã«è¿œå ããŸãïŒ
<div class="form-group"> <%= label f, :password, "Password", class: "control-label" %> <%= password_input f, :password, class: "form-control" %> <%= error_tag f, :password %> </div> <div class="form-group"> <%= label f, :password_confirmation, "Password Confirmation", class: "control-label" %> <%= password_input f, :password_confirmation, class: "form-control" %> <%= error_tag f, :password_confirmation %> </div>
ããŒãžãæŽæ°ããããïŒèªåçã«è¡ãããŸãïŒããŠãŒã¶ãŒããŒã¿ãå
¥åãã[
éä¿¡ ]ãã¿ã³ãã¯ãªãã¯ããŸãã
ãšã©ãŒïŒ
Oops, something went wrong! Please check the errors below.
ããã¯ãã¢ããªã±ãŒã·ã§ã³ãäœãç¥ããªããã¹ã¯ãŒããšãã¹ã¯ãŒã確èªãã£ãŒã«ãã䜿çšããããã§ãã ãã®åé¡ã解決ããã³ãŒããæžããŸãããã
åè·¯ã倿Žããããšããå§ããŸãããã
web / models / user.exãã¡ã€ã«ã§ã次ã®è¡ã远å ã
ãŸã ã
schema "users" do field :username, :string field :email, :string field :password_digest, :string timestamps
passwordãš
password_confirmationã®2ã€ã®ãã£ãŒã«ãã远å ãããŠããããšã«æ³šæããŠãã ããã å®éã«ã¯ããŒã¿ããŒã¹ã«ååšããªããããä»®æ³ãã£ãŒã«ããšããŠå®£èšããŸãããã
ãŠãŒã¶ãŒæ§é ã®ããããã£ãšããŠååšããå¿
èŠããã
ãŸã ã ãŸãã
ãã§ã³ãžã»ããæ©èœã«å€æãé©çšããããšãã§ããŸãã
次ã«ãå¿
é ãã£ãŒã«ãã®ãªã¹ãã«
ïŒpasswordããã³
ïŒpassword_confirmationã远å ããŸãã
def changeset(struct, params \\ %{}) do struct |> cast(params, [:username, :email, :password, :password_confirmation]) |> validate_required([:username, :email, :password, :password_confirmation]) end
test / models / user_test.exsãã¡ã€ã«ãããã¹ããå®è¡ããããšãããšã
ãæå¹ãªå±æ§ãæã€å€æŽã»ããããã¹ãã¯
倱æããŸãã ããã¯ãå¿
èŠãªãã©ã¡ãŒã¿ãŒã«
ïŒpasswordããã³
ïŒpassword_confirmationã远å ãããã
@valid_attrsãæŽæ°ããªãã£ããã
ã§ã ã ãã®è¡ã倿ŽããŸãããïŒ
@valid_attrs %{email: "[email protected]", password: "test1234", password_confirmation: "test1234", username: "testuser"}
ã¢ãã«ãã¹ãã¯åã³ãã¹ããã¯ãã§ãïŒ ããã§ãã³ã³ãããŒã©ãŒã®ãã¹ããä¿®æ£ããå¿
èŠããããŸãã
test / controllers / user_controller_test.exsãã¡ã€ã«ã«ããã€ãã®å€æŽãå ã
ãŸã ã ãŸããæå¹ãªå±æ§ãéžæããŠãå¥ã®å€æ°ã«ãªããžã§ã¯ããäœæããŸãã
@valid_create_attrs %{email: "[email protected]", password: "test1234", password_confirmation: "test1234", username: "testuser"} @valid_attrs %{email: "[email protected]", username: "testuser"}
次ã«ããŠãŒã¶ãŒäœæãã¹ãã倿ŽããŸãã
test "creates resource and redirects when data is valid", %{conn: conn} do conn = post conn, user_path(conn, :create), user: @valid_create_attrs assert redirected_to(conn) == user_path(conn, :index) assert Repo.get_by(User, @valid_attrs) end
ãŠãŒã¶ãŒæŽæ°ãã¹ãïŒ
test "updates chosen resource and redirects when data is valid", %{conn: conn} do user = Repo.insert! %User{} conn = put conn, user_path(conn, :update, user), user: @valid_create_attrs assert redirected_to(conn) == user_path(conn, :show, user) assert Repo.get_by(User, @valid_attrs) end
ãã¹ã
ãåã³ç·è²ã«ãªã£ããããã¹ã¯ãŒãã倿Ž
ã»ããã®ãã€ãžã§ã¹ãã«å€æãã颿°ã远å ããå¿
èŠããããŸãã
def changeset(struct, params \\ %{}) do struct |> cast(params, [:username, :email, :password, :password_confirmation]) |> validate_required([:username, :email, :password, :password_confirmation]) |> hash_password end defp hash_password(changeset) do changeset |> put_change(:password_digest, "ABCDE") end
ä»ã®ãšãããããã·ã¥é¢æ°ã®åäœãå®å®ãããã ãã§ãã ãŸãããªããžã§ã³ãæ£ãã倿ŽãããŠããããšã確èªããŸãããã
httpïŒ// localhostïŒ4000 / usersããŒãžã®ãã©ãŠã¶ã«æ»ãã
New userãªã³ã¯ãã¯ãªãã¯ããŠãä»»æã®ããŒã¿ã§æ°ãããŠãŒã¶ãŒãäœæããŸãã ããã§ããŠãŒã¶ãŒãªã¹ãã«æ°ããè¡ã远å ããããã¹ã¯ãŒããã€ãžã§ã¹ãã
ABCDEã«çãããªããŸãã
ãã®ãã¡ã€ã«ã§ãã¹ããå床å®è¡ããŸãã ãããã¯åæ ŒããŸããã
hash_password颿°ããã¹ãããã®ã«ååãªãã¹ãããããŸããã 远å ããŸãããïŒ
test "password_digest value gets set to a hash" do changeset = User.changeset(%User{}, @valid_attrs) assert get_change(changeset, :password_digest) == "ABCDE" end
ããã¯ã¢ããªã±ãŒã·ã§ã³ã«ãšã£ãŠå€§ããªåé²ã§ãããã»ãã¥ãªãã£ã«ãšã£ãŠã¯ããã»ã©å€§ããªãã®ã§ã¯ãããŸããïŒ
Comeoninã©ã€ãã©ãªããæäŸãããŠãã
BCryptã䜿çšããŠããã¹ã¯ãŒãããã·ã¥ãçŸåšã«è¿
éã«ä¿®æ£ããå¿
èŠããããŸãã
ãããè¡ãã«ã¯ã
mix.exsãã¡ã€ã«ãéãã
ã¢ããªã±ãŒã·ã§ã³ãªã¹ãã«
comeoninã远å ã
ãŸã ã
def application do [mod: {Pxblog, []}, applications: [:phoenix, :phoenix_pubsub, :phoenix_html, :cowboy, :logger, :gettext, :phoenix_ecto, :postgrex, :comeonin]] end
äŸåé¢ä¿ã倿Žããå¿
èŠããããŸãã
{ïŒcomeoninãâã> 2.3â}ã«æ³šæããŠãã ããïŒ
defp deps do [{:phoenix, "~> 1.2.0"}, {:phoenix_pubsub, "~> 1.0"}, {:phoenix_ecto, "~> 3.0"}, {:postgrex, ">= 0.0.0"}, {:phoenix_html, "~> 2.6"}, {:phoenix_live_reload, "~> 1.0", only: :dev}, {:gettext, "~> 0.11"}, {:cowboy, "~> 1.0"}, {:comeonin, "~> 2.3"}] end
å®è¡äžã®ãµãŒããŒã®é»æºãåãã
`mix deps.get`ã³ãã³ããå®è¡ããŸãã ãã¹ãŠãããŸã
ããã° ïŒ
ãããŠããããã¹ãã§ãïŒ ïŒãã³ãã³ã
`iex -S mix phoenix.server`ã§ ããµãŒããŒãåèµ·åã§ããŸãã
å€ã
hash_passwordã¡ãœãã
㯠æªã ãã ãŸããããäžè¬çã«ã¯ãã¹ã¯ãŒããå®éã«ããã·ã¥ããå¿
èŠããããŸãã
Comeoninã©ã€ãã©ãªãŒã远å ããããã
hashpwsaltã¡ãœãããåããçŸãã
Bcryptã¢ãžã¥ãŒã«ãæäŸããã
ãŠãŒã¶ãŒã¢ãã«ã«ã€ã³ããŒããããŸãã
web / models / user.exãã¡ã€ã«ã§ã Pxblog.Webã
䜿çšããçŽåŸã«ä»¥äžã®è¡ã远å ã
ãŸã ïŒmodel ïŒ
import Comeonin.Bcrypt, only: [hashpwsalt: 1]
ç§ãã¡ã¯ä»äœãããŸãããïŒ
Comeoninåå空éãã
Bcryptã¢ãžã¥ãŒã«ã
åãåºã ãarity 1ã§
hashpwsaltã¡ãœãããã€ã³ããŒãã
ãŸãã ãæ¬¡ã®ã³ãŒãã䜿çšããŠã
hash_password颿°ãæ©èœãããŸãã
defp hash_password(changeset) do if password = get_change(changeset, :password) do changeset |> put_change(:password_digest, hashpwsalt(password)) else changeset end end
ãŠãŒã¶ãŒãååºŠäœæããããšããå§ãããŸãïŒ ä»åã¯ãç»é²åŸã
password_digestãã£ãŒã«ãã«æå·åããããã€ãžã§ã¹ãã衚瀺ãããã¯ãã§ãïŒ
ããã§ã¯ã
hash_password颿°ã
å°ãæ¹è¯ããŠã¿ãŸãããã ãŸãããã¹ã¯ãŒãã®æå·åã«ãã£ãŠãã¹ãã劚ããããªãããã«ããã¹ãç°å¢ã®èšå®ã倿Žããå¿
èŠããããŸãã ãããè¡ãã«ã¯ã
config / test.exsãã¡ã€ã«ãéããæ¬¡ã®è¡ãäžçªäžã«è¿œå ããŸãã
config :comeonin, bcrypt_log_rounds: 4
ããã«ããããã¹ãã§ã¯ã»ãã¥ãªãã£ãããé床ãéèŠã«ãªãããããã¹ãå®è¡äžã«ãã¹ã¯ãŒããããŸãæå·åããªãããã«
Comeoninã©ã€ãã©ãªã«æç€ºããŸãïŒ ãããŠæ¬çª
ç°å¢ ïŒ
config / prod.exs file ïŒã§ã¯ãéã«ä¿è·ã匷åããå¿
èŠããããŸãïŒ
config :comeonin, bcrypt_log_rounds: 14
ComeoninãåŒã³åºããã¹ããæžããŸãããã æå·åãæ©èœããããšã確èªãããã ããªã®ã§ã詳现ãå°ãªãããŸãã ãã¡ã€ã«
test / models / user_test.exsã§ ïŒ
test "password_digest value gets set to a hash" do changeset = User.changeset(%User{}, @valid_attrs) assert Comeonin.Bcrypt.checkpw(@valid_attrs.password, Ecto.Changeset.get_change(changeset, :password_digest)) end
ãã¹ãã®ç¯å²ãæ¹åããããã«ã
`if the password = get_changeïŒïŒãæ£ãããªãå ŽåãèŠãŠã¿ãŸãããïŒ
test "password_digest value does not get set if password is nil" do changeset = User.changeset(%User{}, %{email: "[email protected]", password: nil, password_confirmation: nil, username: "test"}) refute Ecto.Changeset.get_change(changeset, :password_digest) end
ãã®å Žåã
password_digestãã£ãŒã«ãã¯ç©ºã®ãŸãŸã«ããŠããå¿
èŠããã
ãŸã ã ç§ãã¡ã¯ã³ãŒãããã¹ãã§ã«ããŒããã®ã«è¯ãä»äºãããŠããŸãïŒ
ã¹ããã4.å§ããŸãããïŒ
æ°ãã
SessionControllerãšä»éãã
SessionViewã远å ããŸãã åçŽãªãã®ããå§ããŸããããæéã®çµéãšãšãã«ãããé©åãªå®è£
ã«ãªããŸãã
web / controllers / session_controller.exãã¡ã€ã«ãäœæããŸãã
defmodule Pxblog.SessionController do use Pxblog.Web, :controller def new(conn, _params) do render conn, "new.html" end end
ãŸãã
web / views / session_view.ex ïŒ
defmodule Pxblog.SessionView do use Pxblog.Web, :view end
ãããŠæåŸã«ã
web / templates / session / new.html.eex ïŒ
<h2>Login</h2>
ã/ãã¹ã³ãŒãã«æ¬¡ã®è¡ã远å ããŸãã
resources "/sessions", SessionController, only: [:new]
ãããã£ãŠãæ°ããã³ã³ãããŒã©ãŒãã«ãŒã¿ãŒã«å«ããŸãã ä»ãããå¿
èŠãšããå¯äžã®æ¹æ³ã¯
newã§ããããã¯æç€ºçã«ç€ºããŠããŸãã ç¹°ãè¿ããŸãããæãåçŽãªæ¹æ³ã§æãå®å®ããåºç€ãååŸããå¿
èŠããããŸãã
ã¢ãã¬ã¹
httpïŒ// localhostïŒ4000 / sessions / newã«ç§»åãããšãèŠåºã
Phoenixãã¬ãŒã ã¯ãŒã¯ã®äžã«
LoginèŠåºãã衚瀺ãããŸãã
ããã«å®éã®ãã©ãŒã ã远å ããŸãã ãããè¡ãã«ã¯ã
web / templates / session / form.html.eexãã¡ã€ã«ãäœæããŸã ïŒ
<%= form_for @changeset, @action, fn f -> %> <%= if f.errors != [] do %> <div class="alert alert-danger"> <p>Oops, something went wrong! Please check the errors below:</p> <ul> <%= for {attr, message} <- f.errors do %> <li><%= humanize(attr) %> <%= message %></li> <% end %> </ul> </div> <% end %> <div class="form-group"> <label>Username</label> <%= text_input f, :username, class: "form-control" %> </div> <div class="form-group"> <label>Password</label> <%= password_input f, :password, class: "form-control" %> </div> <div class="form-group"> <%= submit "Submit", class: "btn btn-primary" %> </div> <% end %>
ãããŠã1è¡ã ãã§
web / templates / session / new.html.eexãã¡ã€ã«ã«ãã©ãŒã ãäœæããŸãããïŒ
<%= render "form.html", changeset: @changeset, action: session_path(@conn, :create) %>
èªåã³ãŒãåèªã¿èŸŒã¿ã®ããã
@ changeset倿°ããŸã å®çŸ©ããŠããªããããããŒãžã«ãšã©ãŒã衚瀺ãããŸãã ãã£ãŒã«ã
ïŒnameãš
ïŒpasswordãæã€ãªããžã§ã¯ãã§äœæ¥ããŠããã®ã§ããããã䜿çšããŸãããïŒ
web / controllers / session_controller.exãã¡ã€ã«ã§ã
ãŠãŒã¶ãŒã¢ãã«ã®ãšã€ãªã¢ã¹ã远å ããŠãããã«ç°¡åã«ã¢ã¯ã»ã¹ã§ããããã«ããå¿
èŠããããŸãã ã¯ã©ã¹ã®å
é ã§ã
Pxblog.Web ,:ã³ã³ãããŒã©ãŒã䜿çšããè¡ã®äžã«ã以äžã远å ããŸãã
alias Pxblog.User
ãããŠã
æ°ãã颿°ã§ã以äžã«ç€ºãããã«ã¬ã³ããŒã³ãŒã«ã倿ŽããŸãã
render conn, "new.html", changeset: User.changeset(%User{})
ããã§ã¯ãæ¥ç¶ãªããžã§ã¯ããã¬ã³ããªã³ã°ãããã³ãã¬ãŒãïŒeexæ¡åŒµãªãïŒãããã³ãã³ãã¬ãŒãå
ã§äœ¿çšããã远å 倿°ã®ãªã¹ããæž¡ãå¿
èŠããããŸãã ãã®å Žåã
changesetïŒãæå®ãã空ã®ãŠãŒã¶ãŒæ§é ãæã€
ãŠãŒã¶ãŒã® Ectoãªããžã§ã³ãæž¡ãå¿
èŠããããŸãã
ããŒãžãæŽæ°ããŸãã æ¬¡ã®ãããªå¥ã®ãšã©ãŒã衚瀺ãããã¯ãã§ãã
No helper clause for Pxblog.Router.Helpers.session_path/2 defined for action :create. The following session_path actions are defined under your router: *:new
ãã®ãã©ãŒã ã§ã¯ããŸã ååšããªããã¹ãåç
§ããŸãã
session_pathãã«ããŒã䜿çšããŠ
@connãªããžã§ã¯ããæž¡ããŸããããŸã äœæãããŠããªããã¹
createãæå®ããŸãã
ååãéããŸããã ããã§ã¯ãã»ãã·ã§ã³ã䜿çšããŠå®éã®ãã°ã€ã³ã®å¯èœæ§ãå®è£
ããŸãããã ãããè¡ãã«ã¯ããã¹ã倿ŽããŸãã
web / router.exãã¡ã€ã«ã§ã次ãå«ããŸã
ïŒ SessionControllerã®èª¬æã«
create ïŒ
resources "/sessions", SessionController, only: [:new, :create]
web / controllers / session_controller.exãã¡ã€ã«ã§ã
Comeoninã©ã€ãã©ãªã®
Bcryptã¢ãžã¥ãŒã«ãã
checkpw颿°ãã€ã³ããŒãããŸãã
import Comeonin.Bcrypt, only: [checkpw: 2]
ãã®è¡ã¯ããComonin.Bcryptã¢ãžã¥ãŒã«ãããarity 2ã®checkpw颿°ã®ã¿ãã€ã³ããŒãããŸãããšè¡šç€ºãããŸããæ¬¡ã«ããŠãŒã¶ãŒããŒã¿ãæäœããscrub_paramsãã©ã°ã€ã³ãæ¥ç¶ããŸãã颿°ã®åã«è¿œå ããŸãã plug :scrub_params, "user" when action in [:create]
scrub_paramsã¯ããŠãŒã¶ãŒå
¥åãã¯ãªã¢ããç¹å¥ãªé¢æ°ã§ããããšãã°ã屿§ãç©ºã®æååãšããŠæž¡ãããå Žåãscrub_paramsã¯ãããnilã«å€æããŠãããŒã¿ããŒã¹ã«ç©ºã®æååãæã€ã¬ã³ãŒããäœæãããªãããã«ããŸããæ¬¡ã«ãäœæã¢ã¯ã·ã§ã³ãåŠçãã颿°ã远å ããŸããSessionControllerã¢ãžã¥ãŒã«ã®äžéšã«é
眮ããŸããããã«ã¯ããããã®ã³ãŒããããã®ã§ããããåè§£ããŠã¿ãŸããããweb / controllers / session_controller.exãã¡ã€ã«ã§ïŒ def create(conn, %{"user" => user_params}) do Repo.get_by(User, username: user_params["username"]) |> sign_in(user_params["password"], conn) end
Repo.get_byã³ãŒãã®æåã®éšåïŒãŠãŒã¶ãŒããŠãŒã¶ãŒåïŒuser_params [âãŠãŒã¶ãŒåâ]ïŒã¯ããŠãŒã¶ãŒåãnilã«äžèŽãããè¿ãããå ŽåãEcto Repoãªããžããªããé©åãªãŠãŒã¶ãŒãååŸããŸãã以äžã¯ããã®åäœããã¹ãããããã®å°ããªåºåã§ãã iex(3)> Repo.get_by(User, username: "flibbity") [debug] SELECT u0."id", u0."username", u0."email", u0."password_digest", u0."inserted_at", u0."updated_at" FROM "users" AS u0 WHERE (u0."username" = $1) ["flibbity"] OK query=0.7ms nil iex(4)> Repo.get_by(User, username: "test") [debug] SELECT u0."id", u0."username", u0."email", u0."password_digest", u0."inserted_at", u0."updated_at" FROM "users" AS u0 WHERE (u0."username" = $1) ["test"] OK query=0.8ms %Pxblog.User{__meta__: %Ecto.Schema.Metadata{source: "users", state: :loaded}, email: "test", id: 15, inserted_at: %Ecto.DateTime{day: 24, hour: 19, min: 6, month: 6, sec: 14, usec: 0, year: 2015}, password: nil, password_confirmation: nil, password_digest: "$2b$12$RRkTZiUoPVuIHMCJd7yZUOnAptSFyM9Hw3Aa88ik4erEsXTZQmwu2", updated_at: %Ecto.DateTime{day: 24, hour: 19, min: 6, month: 6, sec: 14, usec: 0, year: 2015}, username: "test"}
次ã«ããŠãŒã¶ãŒãååŸãããã®ãã§ãŒã³ãsign_in颿°ã«æž¡ããŸãããŸã æžããŠãªãã®ã§ããããŸãããïŒ defp sign_in(user, password, conn) when is_nil(user) do conn |> put_flash(:error, "Invalid username/password combination!") |> redirect(to: page_path(conn, :index)) end defp sign_in(user, password, conn) do if checkpw(password, user.password_digest) do conn |> put_session(:current_user, %{id: user.id, username: user.username}) |> put_flash(:info, "Sign in successful!") |> redirect(to: page_path(conn, :index)) else conn |> put_session(:current_user, nil) |> put_flash(:error, "Invalid username/password combination!") |> redirect(to: page_path(conn, :index)) end end
泚æããå¿
èŠãããäž»ãªããšã¯ããããã®é¢æ°ãå®çŸ©ãããé åºã§ãããããã®æåã®ãã®ã¯ã¬ãŒãæ¡ä»¶ãæã£ãŠããããããã®ã¡ãœããã¯ãã®æ¡ä»¶ãçã§ããå Žåã«ã®ã¿å®è¡ãããŸãããã®ããããŠãŒã¶ãŒãèŠã€ãããªãã£ãå Žåã¯ã察å¿ããã¡ãã»ãŒãžãšãšãã«root_pathã«ãªãã€ã¬ã¯ãããŸãã2çªç®ã®é¢æ°ã¯ãä»ã®ãã¹ãŠã®ã·ããªãªãåŠçããŸãïŒã»ãã¥ãªãã£æ¡ä»¶ãfalseã®å ŽåïŒãcheckpw颿°ã䜿çšããŠãã¹ã¯ãŒãã確èªããŸããæ£ããå Žåã¯ããŠãŒã¶ãŒãã»ãã·ã§ã³å€æ°current_userã«æžã蟌ã¿ããã°ã€ã³æåã«é¢ããã¡ãã»ãŒãžã§ãªãã€ã¬ã¯ãããŸãããã以å€ã®å Žåã¯ãçŸåšã®ãŠãŒã¶ãŒã»ãã·ã§ã³ãã¯ãªã¢ãããšã©ãŒã¡ãã»ãŒãžãèšå®ããŠãã«ãŒãã«ãªãã€ã¬ã¯ãããŸããhttpïŒ// localhostïŒ4000 / sessions / newããŒãžã«ç§»åããŠãåäœã確èªã§ããŸããæ£ããããŒã¿ãããã°ãäžã«å
¥ããééã£ãããŒã¿ã§ã¯ãšã©ãŒã«ãªããŸãããã®ã³ã³ãããŒã©ãŒã®ãã¹ããäœæããå¿
èŠããããŸãããã¡ã€ã«test / controllers / session_controller_test.exsãäœæããæ¬¡ã®ã³ãŒããå
¥åããŸãã defmodule Pxblog.SessionControllerTest do use Pxblog.ConnCase alias Pxblog.User setup do User.changeset(%User{}, %{username: "test", password: "test", password_confirmation: "test", email: "[email protected]"}) |> Repo.insert {:ok, conn: build_conn()} end test "shows the login form", %{conn: conn} do conn = get conn, session_path(conn, :new) assert html_response(conn, 200) =~ "Login" end test "creates a new user session for a valid user", %{conn: conn} do conn = post conn, session_path(conn, :create), user: %{username: "test", password: "test"} assert get_session(conn, :current_user) assert get_flash(conn, :info) == "Sign in successful!" assert redirected_to(conn) == page_path(conn, :index) end test "does not create a session with a bad login", %{conn: conn} do conn = post conn, session_path(conn, :create), user: %{username: "test", password: "wrong"} refute get_session(conn, :current_user) assert get_flash(conn, :error) == "Invalid username/password combination!" assert redirected_to(conn) == page_path(conn, :index) end test "does not create a session if user does not exist", %{conn: conn} do conn = post conn, session_path(conn, :create), user: %{username: "foo", password: "wrong"} assert get_flash(conn, :error) == "Invalid username/password combination!" assert redirected_to(conn) == page_path(conn, :index) end end
æšæºã®ã»ããã¢ãããããã¯ãšGETãªã¯ãšã¹ãã®ããªãåºæ¬çãªãã§ãã¯ããå§ããŸããäœæãã¹ãã¯ããè峿·±ãããã«èŠããŸãïŒ test "creates a new user session for a valid user", %{conn: conn} do conn = post conn, session_path(conn, :create), user: %{username: "test", password: "test"} assert get_session(conn, :current_user) assert get_flash(conn, :info) == "Sign in successful!" assert redirected_to(conn) == page_path(conn, :index) end
æåã®è¡ã¯ãã»ãã·ã§ã³äœæãã¹ã«POSTãªã¯ãšã¹ããéä¿¡ããŠããŸããæ¬¡ã«ãcurrent_userã»ãã·ã§ã³å€æ°ãèšå®ãããŠãããã©ããã確èªãããã§ãã¯ãããããã°ã€ã³ã¡ãã»ãŒãžã衚瀺ãããæåŸã«ãªãã€ã¬ã¯ããè¡ãããŸãããæ®ãã®ãã¹ãã§ã¯ãsign_in颿°ãååŸã§ããä»ã®æ¹æ³ããã§ãã¯ããŸããç¹°ãè¿ããŸããããã¹ãŠãéåžžã«ç°¡åã§ãïŒã¹ããã5. current_userã®æ¹å
ã¡ã€ã³ãã³ãã¬ãŒãã倿ŽããŠããŠãŒã¶ãŒããã°ã€ã³ããŠãããã©ããã«å¿ããŠããŠãŒã¶ãŒåãŸãã¯ãã°ã€ã³ãªã³ã¯ã®ããããã衚瀺ããããã«ããŸãããããè¡ãã«ã¯ãweb / views / layout_view.exãã¡ã€ã«ã«ãã«ããŒã远å ããŸããããã«ãããçŸåšã®ãŠãŒã¶ãŒã«é¢ããæ
å ±ã®ååŸã容æã«ãªããŸãã def current_user(conn) do Plug.Conn.get_session(conn, :current_user) end
web / templates / layout / app.html.eexãã¡ã€ã«ãéããŠãGet Startedãªã³ã¯ã®ä»£ããã«ä»¥äžã远å ããŸãïŒ <li> <%= if user = current_user(@conn) do %> Logged in as <strong><%= user.username %></strong> <br> <%= link "Log out", to: session_path(@conn, :delete, user.id), method: :delete %> <% else %> <%= link "Log in", to: session_path(@conn, :new) %> <% end %> </li>
ããäžåºŠæé ãèŠãŠãããŸããããæåã«è¡ãå¿
èŠãããããšã®1ã€ã¯ãçŸåšã®ãŠãŒã¶ãŒãæ¢ã«ãã°ã€ã³ããŠãããšä»®å®ããŠãçŸåšã®ãŠãŒã¶ãŒã誰ã§ãããã調ã¹ãããšã§ããæåã«é¡ã決å®ããæ¬¡ã«ãªãã¡ã¯ã¿ãªã³ã°ãè¡ããŸãããã³ãã¬ãŒãããã»ãã·ã§ã³ãããŠãŒã¶ãŒãçŽæ¥ã€ã³ã¹ããŒã«ããŸããget_session颿°ã¯Connãªããžã§ã¯ãã®äžéšã§ãããŠãŒã¶ãŒããã°ã€ã³ããŠããå ŽåããŠãŒã¶ãŒã«çµäºãªã³ã¯ã衚瀺ããå¿
èŠããããŸããã»ãã·ã§ã³ãéåžžã®ãªãœãŒã¹ãšèŠãªããããçµäºããã«ã¯ããã®ã¢ã¯ã·ã§ã³ãžã®ãªã³ã¯ã䜿çšããŠã»ãã·ã§ã³ãåé€ããã ãã§ãããŸããçŸåšã®ãŠãŒã¶ãŒã®ååã衚瀺ããå¿
èŠããããŸãããŠãŒã¶ãŒåãååŸã§ããããã«ããŠãŒã¶ãŒæ§é ãcurrent_userã»ãã·ã§ã³å€æ°ã«ä¿åããŸãuser.usernameã䜿çšããŸãããŠãŒã¶ãŒãèŠã€ãããªãå Žåã¯ãå
¥ãå£ãžã®ãªã³ã¯ã衚瀺ããã ãã§ããããã§ã¯ãåã³ãã®ããšãããªãœãŒã¹ãšããŠã»ãã·ã§ã³ãæ€èšããæ°ããªè£å©éã®æ£ããæ¹æ³ã¯ãæ°ããã»ãã·ã§ã³ãäœæããŸãããããããããŒãžãæŽæ°ããåŸãäžè¶³ããŠããæ©èœã«é¢ããå¥ã®ãšã©ãŒã¡ãã»ãŒãžã衚瀺ãããããšã«æ°ã¥ããã§ãããããã§ããã¯ã¹ã幞ãã«ãªãããã«ãå¿
èŠãªãã¹ãæ¥ç¶ããŸãããïŒãã¡ã€ã«å
ã®Web / router.exã ãã§ãªããã»ãã·ã§ã³ãžã®è¿œå ã«ãŒããåé€ããŸãïŒ resources "/sessions", SessionController, only: [:new, :create, :delete]
ãŸã ã³ã³ãããŒã©ãŒã倿Žããå¿
èŠããããŸããweb / controllers / session_controller.exãã¡ã€ã«ã§ã次ã远å ããŸãã def delete(conn, _params) do conn |> delete_session(:current_user) |> put_flash(:info, "Signed out successfully!") |> redirect(to: page_path(conn, :index)) end
current_userããŒãåé€ããã°ãããªã®ã§ãã©ã®ãã©ã¡ãŒã¿ãŒãæ¥ãŠãé¢ä¿ãªãã®ã§ãæåã«ã¢ã³ããŒã¹ã³ã¢ãä»ããŠæªäœ¿çšãšããŠããŒã¯ããŸãããŸããæåããçµäºã¡ãã»ãŒãžãèšå®ããæçš¿ã®ãªã¹ãã«ãªãã€ã¬ã¯ãããŸãããããã§ã倱æãããšã³ããªãå
¥åãçµäºã確èªã§ããŸãããã¹ãŠãè¯ãæ¹åã«é²ãã§ããŸãïŒããããæåã«ããã€ãã®ãã¹ããæžãå¿
èŠããããŸããLayoutViewã®ãã¹ãããå§ããŸããæåã«è¡ãããšã¯ãã³ãŒããççž®ããããã«ãLayoutViewããã³Userã¢ãžã¥ãŒã«ã®ãšã€ãªã¢ã¹ãäœæããããšã§ããæ¬¡ã«ãæ§æãããã¯ã§ããŠãŒã¶ãŒãäœæããããŒã¿ããŒã¹ã«è¿œå ããŸãããããŠãæšæºã¿ãã«{ïŒokãconnïŒbuild_connïŒïŒ}ãè¿ããŸãã defmodule Pxblog.LayoutViewTest do use Pxblog.ConnCase, async: true alias Pxblog.LayoutView alias Pxblog.User setup do User.changeset(%User{}, %{username: "test", password: "test", password_confirmation: "test", email: "[email protected]"}) |> Repo.insert {:ok, conn: build_conn()} end test "current user returns the user in the session", %{conn: conn} do conn = post conn, session_path(conn, :create), user: %{username: "test", password: "test"} assert LayoutView.current_user(conn) end test "current user returns nothing if there is no user in the session", %{conn: conn} do user = Repo.get_by(User, %{username: "test"}) conn = delete conn, session_path(conn, :delete, user) refute LayoutView.current_user(conn) end end
次ã«ããã¹ãèªäœãæ€èšããŸãããããã®æåã®éšåã§ã¯ãã»ãã·ã§ã³ãäœæããLayoutView.current_user颿°ãç¹å®ã®ããŒã¿ãè¿ãããã«èšè¿°ããŸãã2çªç®ã§ã¯ãéã®ç¶æ³ãèæ
®ããŸããã»ãã·ã§ã³ãæç€ºçã«åé€ããcurrent_user颿°ããŠãŒã¶ãŒãè¿ãããšã«åè«ããŸãããŸããåé€ã¢ã¯ã·ã§ã³ãSessionControllerã«è¿œå ããããããã®ãã¹ããäœæããå¿
èŠããããŸãã test "deletes the user session", %{conn: conn} do user = Repo.get_by(User, %{username: "test"}) conn = delete conn, session_path(conn, :delete, user) refute get_session(conn, :current_user) assert get_flash(conn, :info) == "Signed out successfully!" assert redirected_to(conn) == page_path(conn, :index) end
ããã§ã¯ãã»ãã·ã§ã³ã®current_userã空ã§ããããšã確èªããè¿ããããã©ãã·ã¥ã¡ãã»ãŒãžãšãªãã€ã¬ã¯ãã確èªããŸããããã§ãæåã®éšåã¯çµãããŸããã翻蚳è
ããã®éèŠãªçµè«
ç§ã¯ãã®èšäºãšã·ãªãŒãºå
šäœã®ç¿»èš³ã®äž¡æ¹ã翻蚳ããçŽ æŽãããä»äºãããŸãããç§ãä»ãç¶ããŠããããšããããã£ãŠãèšäºèªäœãŸãã¯RuNetã§Elixirãæ®åãããåªåãæ°ã«å
¥ã£ãå Žåã¯ããã©ã¹ãã³ã¡ã³ããåæçš¿ã§èšäºããµããŒãããŠãã ãããããã¯ç§å人ã«ãšã£ãŠãããšãªã¯ãµãŒã³ãã¥ããã£å
šäœã«ãšã£ãŠãéåžžã«éèŠã§ããã·ãªãŒãºã®ä»ã®èšäº
- ãšã³ããªãŒ
- ãã°ã€ã³
- 圹å²ã远å
- ã³ã³ãããŒã©ãŒã§åœ¹å²ãåŠçããŸã
- ExMachinaãæ¥ç¶ããŸã
- ããŒã¯ããŠã³ã®ãµããŒã
- ã³ã¡ã³ãã远å
- ã³ã¡ã³ãã§çµäº
- ãã£ã³ãã«
- ãã£ãã«ãã¹ã
- ãããã«
ãã¹ãŠã®äžæ£ç¢ºãããšã©ãŒãäžååãªç¿»èš³ã«ã€ããŠã¯ãå人çãªã¡ãã»ãŒãžã§æžããŠãã ãããç§ã¯ããã«ãããä¿®æ£ããŸããäºåã«æè¬ããŸãã