Phoenixのルーティング定義を変更してみる

# 最初に
この文章は、Phoenixのガイドを斜めに読みながら試した結果を書いています。
元文章の読み間違い等がありましたらコメントお願いします。

# ネストしたリソースに対するルーティング定義
## 設定ファイルの修正
[デモアプリ作成時](http://qiita.com/ak-ymst/items/b000461f4deeffc96f9f)、ある記事へコメントを投稿する機能に

```
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