mmag

ハマったことメモなど

Phoenixでresourcesをネストさせるときにaliasも設定できる

普通にやるならこうする。

scope "/v1", MyApp do
  pipe_through :api

  resources "/users", UserController, only: [:index] do
    resources "/articles", ArticleController, only: [:index]
  end
end

生成されるルーティングはこれ。

$ mix phx.routes
        user_path  GET  /v1/users                    MyApp.UserController :index
user_article_path  GET  /v1/users/:user_id/articles  MyApp.ArticleController :index

ただしこれだと/v1/articlesを入れたときに

scope "/v1", MyApp do
  pipe_through :api

  resources "/users", UserController, only: [:index] do
    resources "/articles", ArticleController, only: [:index]
  end
  resources "/articles", ArticleController, only: [:index]
end
$ mix phx.routes
        user_path  GET  /v1/users                    MyApp.UserController :index
user_article_path  GET  /v1/users/:user_id/articles  MyApp.ArticleController :index
     article_path  GET  /v1/articles                 MyApp.ArticleController :index

というルーティングになるので、/v1/users/:user_id/articlesと同じコントローラを使うことになる。それでいいならOKだけど、別にしたいときはscope/2でaliasを入れてあげる。

scope "/v1", MyApp do
  pipe_through :api

  resources "/users", UserController, only: [:index] do
    scope alias: User do
      resources "/articles", ArticleController, only: [:index]
    end
  end
  resources "/articles", ArticleController, only: [:index]
end
$ mix phx.routes
        user_path  GET  /v1/users                    MyApp.UserController :index
user_article_path  GET  /v1/users/:user_id/articles  MyApp.User.ArticleController :index
     article_path  GET  /v1/articles                 MyApp.ArticleController :index

MyApp.User.ArticleControllerMyApp.ArticleControllerに分けられる。ここまでは何も特別なことは言ってなくて、ドキュメントに書いてあるしわざわざブログ書くようなことじゃない。自分もこんな風にscope/2使うのが普通と思っていたんだけど、最近うろ覚えで「こうだっけ?」って↓のように書いたら同じ動きをした。

scope "/v1", MyApp do
  pipe_through :api

  resources "/users", UserController, only: [:index], alias: User do # ここに alias
    resources "/articles", ArticleController, only: [:index]
  end
  resources "/articles", ArticleController, only: [:index]
end
$ mix phx.routes
        user_path  GET  /v1/users                    MyApp.UserController :index
user_article_path  GET  /v1/users/:user_id/articles  MyApp.User.ArticleController :index
     article_path  GET  /v1/articles                 MyApp.ArticleController :index

ソースを追っていくとhttps://github.com/phoenixframework/phoenix/blob/v1.4.1/lib/phoenix/router/resource.ex#L32にたどり着いて、確かにresourcesaliasオプション受け入れてくれるんだなーって感じ。でもhttps://hexdocs.pm/phoenix/1.4.1/Phoenix.Router.html#resources/4には言及がなかったので、とりあえずプルリク投げといた。