最初に
この文章は、Phoenixのガイドを斜めに読みながら試した結果を書いています。
元文章の読み間違い等がありましたらコメントお願いします。
ネストしたリソースに対するルーティング定義
設定ファイルの修正
デモアプリ作成時、ある記事へコメントを投稿する機能に
POST /posts/:id/comment
というルートを割り当てるために、
scope "/", PhoenixSample do
pipe_through :browser # Use the default browser stack
get "/", PageController, :index
resources "/posts", PostController
post "/posts/:id/comments", PostController, :add_comment # add comment route
end
という形で定義を行った。
しかし、こういったネストしたリソースに対しては
scope "/", PhoenixSample do
pipe_through :browser # Use the default browser stack
get "/", PageController, :index
resources "/posts", PostController do
resources "/comments", CommentController
end
# post "/posts/:id/comments", PostController, :add_comment
end
という形で定義することができるようだ。
試しにルート一覧を見てみると、
page_path GET / PhoenixSample.PageController :index
post_path GET /posts PhoenixSample.PostController :index
post_path GET /posts/:id/edit PhoenixSample.PostController :edit
post_path GET /posts/new PhoenixSample.PostController :new
post_path GET /posts/:id PhoenixSample.PostController :show
post_path POST /posts PhoenixSample.PostController :create
post_path PATCH /posts/:id PhoenixSample.PostController :update
PUT /posts/:id PhoenixSample.PostController :update
post_path DELETE /posts/:id PhoenixSample.PostController :delete
post_comment_path GET /posts/:post_id/comments PhoenixSample.CommentController :index
post_comment_path GET /posts/:post_id/comments/:id/edit PhoenixSample.CommentController :edit
post_comment_path GET /posts/:post_id/comments/new PhoenixSample.CommentController :new
post_comment_path GET /posts/:post_id/comments/:id PhoenixSample.CommentController :show
post_comment_path POST /posts/:post_id/comments PhoenixSample.CommentController :create
post_comment_path PATCH /posts/:post_id/comments/:id PhoenixSample.CommentController :update
PUT /posts/:post_id/comments/:id PhoenixSample.CommentController :update
post_comment_path DELETE /posts/:post_id/comments/:id PhoenixSample.CommentController :delete
ずらりとcomment関係のルーティングが追加されていることがわかる。
しかし、今回欲しいのはコメント追加の機能だけなので、更に定義を変更。
scope "/", PhoenixSample do
pipe_through :browser # Use the default browser stack
get "/", PageController, :index
resources "/posts", PostController, expect: [:delete] do
resources "/comments", CommentController, only: [:create]
end
# post "/posts/:id/comments", PostController, :add_comment
end
必要なコメント追加のルートだけを追加し、ついでにもともと不要だった記事の削除のルートを除外する。
再び確認してみると、
page_path GET / PhoenixSample.PageController :index
post_path GET /posts PhoenixSample.PostController :index
post_path GET /posts/:id/edit PhoenixSample.PostController :edit
post_path GET /posts/new PhoenixSample.PostController :new
post_path GET /posts/:id PhoenixSample.PostController :show
post_path POST /posts PhoenixSample.PostController :create
post_path PATCH /posts/:id PhoenixSample.PostController :update
PUT /posts/:id PhoenixSample.PostController :update
post_path DELETE /posts/:id PhoenixSample.PostController :delete
post_comment_path POST /posts/:post_id/comments PhoenixSample.CommentController :create
想定通り、コメント追加だけが追加されている。
その他修正
あとは、テンプレートの修正とコントローラの追加を行う。
mixコマンドにはコントローラだけを作成するようなタスクは存在しない模様。
(ググるとphoenix.gen.controllerというものが出てくるが、おそらく古いバージョンのもの)
しょうがないので、web/controller/post_controller.ex必要な部分だけコピペし、
create関数だけ
def create(conn, %{"post_id" => post_id, "comment" => post_params}) do
post = Repo.get!(Post, post_id)
changeset = Comment.changeset(%Comment{post_id: post.id}, post_params)
case Repo.insert(changeset) do
{:ok, _post} ->
conn
|> put_flash(:info, "Comment create successfully.")
|> redirect(to: post_path(conn, :show, post))
{:error, changeset} ->
conn
|> put_flash(:info, "Error occured.")
|> redirect(to: post_path(conn, :show, post))
end
end
と、先日作成したadd_comment関数を移植したものに書き換えて終了。
テンプレートについては、web/template/post/show.eexのコメント投稿フォームのアクションを
<%= form_for @comment_changeset, post_comment_path(@conn, :create, @post), fn f -> %>
と新たに定義された関数に差し替えて終了。
これで、新しい定義でも動くようになるはずです。
prefixを含んだルートを定義する
例えば、api用のルートはすべて
/api/xxx/yyy
と先頭に/apiというprefixをつけて定義したい場合は
scope "/api", PhoenixSample do
pipe_through :api
resources "/posts", ApiPostController
end
このようにスコープを作り、その内部で定義すると、
api_post_path GET /api/posts PhoenixSample.ApiPostController :index
api_post_path GET /api/posts/:id/edit PhoenixSample.ApiPostController :edit
api_post_path GET /api/posts/new PhoenixSample.ApiPostController :new
api_post_path GET /api/posts/:id PhoenixSample.ApiPostController :show
api_post_path POST /api/posts PhoenixSample.ApiPostController :create
api_post_path PATCH /api/posts/:id PhoenixSample.ApiPostController :update
PUT /api/posts/:id PhoenixSample.ApiPostController :update
api_post_path DELETE /api/posts/:id PhoenixSample.ApiPostController :delete
このように、スコープで指定したprefix込のルートが定義される。
参考サイト
Phoenix GUIDE : http://www.phoenixframework.org/docs/routing