Ecto error in Phoenix - value `"new"` in `where` cannot be cast to type :id in query

Hi everyone,

I’m trying to create a simple blog in phoenix 1.3 , I’ve done this with 1.2 before. After generating the post resource with the phx.gen.html command and adding coherence I keep getting this weird interaction. In order to keep posts read-only without a session I added the following to the public resource route:

resources "/posts", PostController, only: [:index, :show]

This works in 1.2 but in 1.3 it gives me the following error when I try to create a new post using the generated resources.

deps/ecto/lib/ecto/repo/queryable.ex:341: value `"new"` in `where` cannot be cast to type :id in query:

This error goes away when I remove :show or when I add :new to the public routes.

Why is this and how can I fix it?

How are you executing new post creation? Because you have defined only two actions for post.[quote=“Zesky665, post:1, topic:10041”]
only: [:index, :show]
[/quote]

Need more details and I think we will find the problem.

The rest of the actions are in the :protected scope set up with coherence, here is what mine looks like.

   scope "/", BlogAppWeb do
     pipe_through :browser
     get "/", PageController, :index
     resources "/posts", PostController,  only: [:index, :show]
     # Add public routes below
   end

   scope "/", BlogAppWeb do
     pipe_through :protected
     resources "/posts", PostController
     # Add protected routes below
   end

The idea is that you can use the :index and :show actions anytime but you need to be logged in to use any of the others like :new. This works for other actions like :edit but not for :new.

I think you should define actions for the second resource too with only:.

Could you paste a screenshot of the full error and full error stack?

Here’s a image of the error screen : https://imgur.com/a/pZE5I
Terminal output: https://imgur.com/a/ZvZOM

I tried defining actions for the second one with only: , didn’t work.

The :show route needs to be after the :new route, otherwise it’ll try to show you the resource with the id of new.

2 Likes

I don’t think that routing is going to work, won’t the first scope match all requests and none will go to the authed scope? Or will Phoenix try other scopes if there is no match for a route inside a scope?

The way it’s supposed to work at least is that, if you go into one of the routes that is not in the public route, it will give you a login screen. This works with every other action/route but it throws this error when using the :new action.

This will work:

   scope "/", BlogAppWeb do
     pipe_through :protected
     resources "/posts", PostController, except: [:index, :show]
     # Add protected routes below
   end

   scope "/", BlogAppWeb do
     pipe_through :browser
     get "/", PageController, :index
     resources "/posts", PostController,  only: [:index, :show]
     # Add public routes below
   end
2 Likes

Thank you :slight_smile: This works.

But why? Does phoenix/elixir match against routes in the order in which they appear in router.ex?

1 Like

It does. Routes are just macros, which at compile time will be converted to standard functions, which work by the rules of pattern matching.

2 Likes

Yea, as I mentioned, the only: part looked weird to me, but didn’t understand right away that its main problem. :slight_smile: