D.R
D.R

Reputation: 859

protocol Enumerable not implemented for nil (phoenix-framework)

I added a function "payment" in a order controller and added a route for that.

def payment(conn, %{"id" => id}) do
  foods = Repo.all(Food)
  order =
    Repo.get!(assoc(conn.assigns[:table], :orders), id)
    |> Repo.preload(order_items: :food)
  order_item_changeset =
    order
    |> build_assoc(:order_items)
    |> Pos1.OrderItem.changeset()
  order_changeset = Order.changeset(order)

  render(conn, "payment.html", order: order, order_item_changeset: order_item_changeset, order_changeset: order_changeset, foods: foods, payment: @payment)
end

resources "/tables", TableController do
  resources "/orders", OrderController do
    get "/payment", OrderController, :payment
end

I added route for payment under table and order because payment has to show its table number and order id. And I added a link to payment page in show.html of order template. However, it causes Protocol.UndefinedError.

[error] #PID<0.9096.0> running Pos1.Endpoint terminated
Server: localhost:4000 (http)
Request: GET /tables/1/orders/14
** (exit) an exception was raised:
    ** (Protocol.UndefinedError) protocol Enumerable not implemented for nil
        (elixir) lib/enum.ex:1: Enumerable.impl_for!/1
        (elixir) lib/enum.ex:116: Enumerable.reduce/3
        (elixir) lib/enum.ex:1486: Enum.reduce/3
        (pos1) Pos1.Router.Helpers.segments/3
        (pos1) web/router.ex:1: Pos1.Router.Helpers.table_order_order_path/5
        (pos1) web/templates/order/show.html.eex:59: Pos1.OrderView."show.html"/1
        (pos1) web/templates/layout/app.html.eex:41: Pos1.LayoutView."app.html"/1
        (phoenix) lib/phoenix/view.ex:344: Phoenix.View.render_to_iodata/3
        (phoenix) lib/phoenix/controller.ex:633: Phoenix.Controller.do_render/4
        (pos1) web/controllers/order_controller.ex:1: Pos1.OrderController.action/2
        (pos1) web/controllers/order_controller.ex:1: Pos1.OrderController.phoenix_controller_pipeline/2
        (pos1) lib/phoenix/router.ex:261: Pos1.Router.dispatch/2
        (pos1) web/router.ex:1: Pos1.Router.do_call/2
        (pos1) lib/pos1/endpoint.ex:1: Pos1.Endpoint.phoenix_pipeline/1
        (pos1) lib/plug/debugger.ex:93: Pos1.Endpoint."call (overridable 3)"/2
        (pos1) lib/phoenix/endpoint/render_errors.ex:34: Pos1.Endpoint.call/2
        (plug) lib/plug/adapters/cowboy/handler.ex:15: Plug.Adapters.Cowboy.Handler.upgrade/4
        (cowboy) src/cowboy_protocol.erl:442: :cowboy_protocol.execute/4

How can I solve this? Should I use other approach to define function payment?

This is code from web/templates/order/show.html.eex:59

 <%= link "Confirm orders", to: table_order_order_path(@conn, :payment, @table, @order, @payment) %> 




<%= if @payment do %>
<%= link "Confirm orders", to: table_order_order_path(@conn, :payment, @table, @order, @payment) %>
<% end %>

Upvotes: 1

Views: 8365

Answers (1)

tkowal
tkowal

Reputation: 9289

The error protocol Enumerable not implemented for nil means that you are passing nil somewhere where a list or enumerable should be used.

If you look down the stack, you can see it is: Pos1.Router.Helpers.table_order_order_path/5 Order path probably takes order or order id which is NULL in the database. You can simply try to print order and order_item_changeset in the controller to see which one is problematic.

If you look a little lower again it tells you that your problem lies in template: web/templates/order/show.html.eex:59. Try this in your template:

<%= if @order do %> #or whichever value is nil
  your code here
<% end %>

Upvotes: 8

Related Questions