Hacker News new | ask | show | jobs
by dhucerbin 1101 days ago
Is it possible to get on Phoenix nested controllers? Like in remix.run, where for each route segment we get one controller/view. It’s really generalised version of layouts.

When I was looking into Phoenix all routes, no matter how nested, had to resolve to single controller. That meant that controller for path `/user/settings/privacy` was also responsible for getting data to display users sidebar.

2 comments

Sounds like you want to define some shared behaviour that can be applied across a set of controllers? Phoenix doesn't have "nested" controllers like you describe, but you might be able to do what you want using a plug. Something like:

  # lib/your_app_web/controllers/user_sidebar.ex
  defmodule YourAppWeb.UserSidebar do
    def load_sidebar(conn, _params) do
      data = SomeModule.whatever_loads_your_sidebar_data()
      assign(conn, :sidebar, data)
    end
  end

  # then in router.ex:
  import YourAppWeb.UserSidebar

  pipeline :users do
    plug :load_sidebar
  end

  scope "/users", YourAppWeb do
    pipe_through [:browsers, :user]

    get "settings/privacy", SettingsController, :privacy
    # and all other routes that need this sidebar
    # …
  end
Then in your controller action `SettingsController.privacy/2`, the incoming `conn` will already have `sidebar` assigned because it's been passed through `load_sidebar`.

Remember that an HTTP request/response cycle in Phoenix is fundamentally just a list of transformations that are applied to a `%Plug.Conn{}`. If you want the same behaviour to apply to multiple controller actions, you can just define that behaviour in a plug function (i.e. a two-arity function that takes and returns a conn), then pass your conn through that plug before it reaches your controller actions.

Typo, too late to edit it now, but `pipe_through [:browsers, :user]` should be `pipe_through [:browsers, :users]` (i.e. `:users` not `:user`.)
In LiveView you can use hooks or LiveComponents for that kind of thing. Not sure about regular controllers as I've never actually built an app using them, heh.