Previous Clause Always Matches: Are These Not Different Routes?

I’m trying to implement a new version of an invite system. The plan is, for now, to leave the old route open for users who may have the previous version of the invite, while opening up a new route for the new invite style.

Presently the definition looks like this:

  scope "/clubs/invite/", ClubWeb.Accounts, as: :club do
    pipe_through [:browser]

    get "/:token", InvitationController, :new
    post "/:token", InvitationController, :create
    get "/:uuid", UserInviteController, :new
    post "/:uuid", UserInviteController, :create
  end

When I saved, I saw a warning for each uuid line, referring to each token line before it:

warning: this clause cannot match because a previous clause at line xxx always matches

I have to admit, that confuses me a bit. Are these not different routes?

Nope - the :token / :uuid segments are your keywords for what’s captured in params, not a fixed part of the path. So you’ve specified GET and POST versions of a single route, /clubs/invite/[segment]. The final segment of the requested path will be captured as :token, with the uuid variants never reached during the matching operation.

I guess the best bet would be to create a new scope with a different path for the new api version. I’m new to elixir/phoenix though so perhaps someone else will chime in on the most elegant approach.

1 Like

There is no way the system can understand if You pass a token or an uuid. Therefore :uuid will never be matched because the :token clause will match first.

You could try

get "/invitations/:token", InvitationController, :new
get "/user_invitations/:uuid", UserInviteController, :new
3 Likes

And if path is predefined, inside controller(it must be only one though) it’s possible to determine if identifier is token or uuid

3 Likes

Man, that seems a lot simpler than my head made it out to be. Thank you all for helping me sort through this one.