phoenixframework / phoenix

Peace of mind from prototype to production
https://www.phoenixframework.org
MIT License
21.38k stars 2.87k forks source link

Route not found - Restart of Server is required. #1437

Closed bmalum closed 8 years ago

bmalum commented 8 years ago

I noticed after adding a custom action to a nested resource that Phoenix claims the route can not be found. I have discussed the problem with @Gazler in the Elixir IRC channel and he said the server restart should be not necessary - I tried to reproduce the Issue and will describe you all the steps I've done. Thanks to @Gazler for taking time to help me.

Creating a simple hello_phoenix

➜  Elixir  mix phoenix.new hello_phoenix
* creating hello_phoenix/config/config.exs
* creating hello_phoenix/config/dev.exs
* creating hello_phoenix/config/prod.exs
* creating hello_phoenix/config/prod.secret.exs
* creating hello_phoenix/config/test.exs
* creating hello_phoenix/lib/hello_phoenix.ex
* creating hello_phoenix/lib/hello_phoenix/endpoint.ex
* creating hello_phoenix/test/controllers/page_controller_test.exs
* creating hello_phoenix/test/views/error_view_test.exs
* creating hello_phoenix/test/views/page_view_test.exs
* creating hello_phoenix/test/views/layout_view_test.exs
* creating hello_phoenix/test/support/conn_case.ex
* creating hello_phoenix/test/support/channel_case.ex
* creating hello_phoenix/test/test_helper.exs
* creating hello_phoenix/web/channels/user_socket.ex
* creating hello_phoenix/web/controllers/page_controller.ex
* creating hello_phoenix/web/templates/layout/app.html.eex
* creating hello_phoenix/web/templates/page/index.html.eex
* creating hello_phoenix/web/views/error_view.ex
* creating hello_phoenix/web/views/layout_view.ex
* creating hello_phoenix/web/views/page_view.ex
* creating hello_phoenix/web/router.ex
* creating hello_phoenix/web/web.ex
* creating hello_phoenix/mix.exs
* creating hello_phoenix/README.md
* creating hello_phoenix/lib/hello_phoenix/repo.ex
* creating hello_phoenix/test/support/model_case.ex
* creating hello_phoenix/priv/repo/seeds.exs
* creating hello_phoenix/.gitignore
* creating hello_phoenix/brunch-config.js
* creating hello_phoenix/package.json
* creating hello_phoenix/web/static/css/app.css
* creating hello_phoenix/web/static/js/app.js
* creating hello_phoenix/web/static/js/socket.js
* creating hello_phoenix/web/static/assets/robots.txt
* creating hello_phoenix/web/static/assets/images/phoenix.png
* creating hello_phoenix/web/static/assets/favicon.ico

Fetch and install dependencies? [Yn] Y
* running npm install && node node_modules/brunch/bin/brunch build
* running mix deps.get

We are all set! Run your Phoenix application:

    $ cd hello_phoenix
    $ mix ecto.create
    $ mix phoenix.server

You can also run your app inside IEx (Interactive Elixir) as:

    $ iex -S mix phoenix.server

Creating a Post resource like in the Guide

➜  hello_phoenix  mix phoenix.gen.html Post posts body:string word_count:integer
* creating web/controllers/post_controller.ex
* creating web/templates/post/edit.html.eex
* creating web/templates/post/form.html.eex
* creating web/templates/post/index.html.eex
* creating web/templates/post/new.html.eex
* creating web/templates/post/show.html.eex
* creating web/views/post_view.ex
* creating test/controllers/post_controller_test.exs
* creating priv/repo/migrations/20151230105511_create_post.exs
* creating web/models/post.ex
* creating test/models/post_test.exs

Add the resource to your browser scope in web/router.ex:

    resources "/posts", PostController

Remember to update your repository by running migrations:

    $ mix ecto.migrate

Creating the second resource.

➜  hello_phoenix  mix phoenix.gen.html Comment comments body:string word_count:integer
* creating web/controllers/comment_controller.ex
* creating web/templates/comment/edit.html.eex
* creating web/templates/comment/form.html.eex
* creating web/templates/comment/index.html.eex
* creating web/templates/comment/new.html.eex
* creating web/templates/comment/show.html.eex
* creating web/views/comment_view.ex
* creating test/controllers/comment_controller_test.exs
* creating priv/repo/migrations/20151230105832_create_comment.exs
* creating web/models/comment.ex
* creating test/models/comment_test.exs

Add the resource to your browser scope in web/router.ex:

    resources "/comments", CommentController

Remember to update your repository by running migrations:

    $ mix ecto.migrate

➜  hello_phoenix

Migrating the DB

➜  hello_phoenix  mix ecto.migrate
Compiled web/models/comment.ex
Compiled web/models/post.ex

== Compilation error on file web/controllers/comment_controller.ex ==
** (CompileError) web/controllers/comment_controller.ex:25: function comment_path/2 undefined
    (stdlib) lists.erl:1337: :lists.foreach/2
    (stdlib) erl_eval.erl:669: :erl_eval.do_apply/6
    (elixir) lib/kernel/parallel_compiler.ex:100: anonymous fn/4 in Kernel.ParallelCompiler.spawn_compilers/8

➜  hello_phoenix 

To avoid compiler error i have removed the Comment-Templates and |> redirect(to: post_comment_path(conn, :index)) Lines - this should not cause the bug

➜  hello_phoenix  mix phoenix.routes
Compiled web/views/error_view.ex
Compiled web/views/comment_view.ex
Compiled web/views/page_view.ex
Compiled web/controllers/page_controller.ex
Compiled web/views/layout_view.ex
web/controllers/comment_controller.ex:35: warning: variable conn is unused
web/controllers/comment_controller.ex:35: warning: variable id is unused
web/controllers/comment_controller.ex:49: warning: variable comment is unused
Compiled web/controllers/comment_controller.ex
Compiled web/controllers/post_controller.ex
Compiled web/views/post_view.ex
Compiled web/router.ex
Compiled lib/hello_phoenix/endpoint.ex
Generated hello_phoenix app
                page_path  GET     /                                              HelloPhoenix.PageController :index
                post_path  GET     /api/posts                                     HelloPhoenix.PostController :index
                post_path  GET     /api/posts/:id/edit                            HelloPhoenix.PostController :edit
                post_path  GET     /api/posts/new                                 HelloPhoenix.PostController :new
                post_path  GET     /api/posts/:id                                 HelloPhoenix.PostController :show
                post_path  POST    /api/posts                                     HelloPhoenix.PostController :create
                post_path  PATCH   /api/posts/:id                                 HelloPhoenix.PostController :update
                           PUT     /api/posts/:id                                 HelloPhoenix.PostController :update
                post_path  DELETE  /api/posts/:id                                 HelloPhoenix.PostController :delete
        post_comment_path  GET     /api/posts/:post_id/comments                   HelloPhoenix.CommentController :index
        post_comment_path  GET     /api/posts/:post_id/comments/:id/edit          HelloPhoenix.CommentController :edit
        post_comment_path  GET     /api/posts/:post_id/comments/new               HelloPhoenix.CommentController :new
        post_comment_path  GET     /api/posts/:post_id/comments/:id               HelloPhoenix.CommentController :show
        post_comment_path  POST    /api/posts/:post_id/comments                   HelloPhoenix.CommentController :create
        post_comment_path  PATCH   /api/posts/:post_id/comments/:id               HelloPhoenix.CommentController :update
                           PUT     /api/posts/:post_id/comments/:id               HelloPhoenix.CommentController :update
        post_comment_path  DELETE  /api/posts/:post_id/comments/:id               HelloPhoenix.CommentController :delete
post_comment_comment_path  GET     /api/posts/:post_id/comments/:comment_id/test  HelloPhoenix.CommentController :comment

➜  hello_phoenix

We can see that /api/posts/:post_id/comments/:comment_id/test does exist in mix phoenix.routes output ... Notice that the server has been started before the route has been added and mix phoenix.routes was called.

➜  hello_phoenix  mix phoenix.server
[info] Running HelloPhoenix.Endpoint with Cowboy on http://localhost:4000
30 Dec 12:14:24 - info: compiled 5 files into 2 files, copied 3 in 2327ms
[info] GET /api/posts/1/comments/1/test
[info] GET /api/posts/1/comments/1/test
[info] GET /api/posts/1/comments/1/test

here is the response:
response.txt

josevalim commented 8 years ago

I believe we are missing the step where you add the routes to your web/router.ex. For example, when is "/api/posts/1/comments/1/test" added?

bmalum commented 8 years ago

Oh my fault - after Creating the second resource web/router looks like this:

defmodule HelloPhoenix.Router do
  use HelloPhoenix.Web, :router

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_flash
    plug :protect_from_forgery
    plug :put_secure_browser_headers
  end

  pipeline :api do
    plug :accepts, ["json"]
  end

  scope "/", HelloPhoenix do
    pipe_through :browser # Use the default browser stack

    get "/", PageController, :index
  end

  # Other scopes may use custom stacks.
  scope "/api", HelloPhoenix do
     pipe_through :api
     resources "posts", PostController do
      resources "comments", CommentController do
        get "test", CommentController, :test 
      end
    end
  end
end
chrismccord commented 8 years ago

Can you verify that the above router is the one that triggered this? It should have raised an error with get "test" since it missing a forward slash, and the output in the mix task is :comment action, not :test

chrismccord commented 8 years ago

I can't recreate this, but I did confirm that we have a regression that allows router paths without a forward slash, we should be raising. Can you verify your elixir version?

bmalum commented 8 years ago

I'm pretty sure, the first try was with comment in the route, the second one with test. I will try on another System at the evening again.

My Elixir Version is: Elixir 1.1.1

josevalim commented 8 years ago

@chrismccord I thought at some point we decided to drop the restriction? I can't remember anymore.

hectorip commented 8 years ago

@chrismccord @josevalim yes you removed the restriction it didn't happen to me but I have to restart the server every time I add a new route.

chrismccord commented 8 years ago

@hectorip let's rule out your editor using a syntax checker plugin that recompiles the project behind the scenes. I'm willing to be that is what is happening, causing the running server to not pick up any changes because it sees no files that need recompiled/reloaded

bmalum commented 8 years ago

Hi to all - I just had to restart my Server on Elixir 1.1.1 on a completely different setup and machine - I immediately committed the changes and pasted the phoenix.server output in the commit message.

You can find the commit here: bmalum/Constructeev_Elixir@21166a030b40b81c42161af0bdf2a335a987419e

josevalim commented 8 years ago

@bmalum so is it working as expected now?

chrismccord commented 8 years ago

@bmalum, are you using an editor plugin that does syntax checking? These have been known to cause reloading issues since they recompile the project behind the scenes.

bmalum commented 8 years ago

@chrismccord - good hint. I'm using SublimeText with several Plugins (Elixir, Angular …) - I tried again with @Gazler today using a plain VI - everything worked fine. I thought Elixir Package from Sublime does not compile in background. Very Strange :/

chrismccord commented 8 years ago

I'm closing this for now. If you are able to recreate, please reopen. Thanks!

malloryerik commented 7 years ago

This happened to me, in VS Code with the main Elixir package installed, while I was trying the first tutorial from phoenixproject.org. The problem, router.ex wasn't loading without a server restart.

I switched to emacs and it all worked as expected.

In bash, the error looked like this:

[debug] ** (Phoenix.Router.NoRouteError) no route found for GET /hello/John (HelloWeb.Router)
    (hello) lib/hello_web/router.ex:1: HelloWeb.Router.__match_route__/4
    (hello) lib/phoenix/router.ex:303: HelloWeb.Router.call/2
    (hello) lib/hello_web/endpoint.ex:1: HelloWeb.Endpoint.plug_builder_call/2
    (hello) lib/plug/debugger.ex:99: HelloWeb.Endpoint."call (overridable 3)"/2
    (hello) lib/hello_web/endpoint.ex:1: HelloWeb.Endpoint.call/2
    (plug) lib/plug/adapters/cowboy/handler.ex:15: Plug.Adapters.Cowboy.Handler.upgrade/4
    (cowboy) /Users/[...]/phoenix/hello/deps/cowboy/src/cowboy_protocol.erl:442: :cowboy_protocol.execute/4