I’m trying to test the index action of my controller, but I’m getting this error while doing it:
** (ArgumentError) maps cannot be converted to_param. A struct was expected, got: %{club_id: 0}
This is my controller:
defmodule DummyApiWeb.ItemController do
use DummyApiWeb, :controller
alias DummyApi.Items
def index(conn, %{"club_id" => club_id }) do
items = Items.list_items(club_id)
render(conn, "index.json", items: items)
end
...
end
And this is my test:
test "lists all items", %{conn: conn} do
conn = get(conn, Routes.club_item_path(conn, :index, %{"club_id" => 0 }))
assert json_response(conn, 200)["data"] == []
end
dom
May 18, 2019, 11:10pm
2
Can you please include the stacktrace from the error message?
stacktrace:
(phoenix) lib/phoenix/param.ex:77: Phoenix.Param.Map.to_param/1
(dummy_api) DummyApiWeb.Router.Helpers.club_item_path/4
test/dummy_api_web/controllers/item_controller_test.exs:32: (test)
Seems like your route helper expects a param for the url (:whatever
in the router) in the place you‘re passing the GET query.
dom
May 19, 2019, 8:25pm
5
As LostKobrakai suggests - you probably want Routes.club_item_path(conn, :index, 0)
. Check out the examples:
https://hexdocs.pm/phoenix/routing.html#more-on-path-helpers
But why is it that when I try to use the update action like this:
conn = put(conn, Routes.club_item_path(conn, :update, item.club_id, item.id, @update_attrs))
I’m getting this ?:
** (ArgumentError) argument error
code: conn = put(conn, Routes.club_item_path(conn, :update, item.club_id, item.id, @update_attrs))
This is my update action:
def update(conn, %{"club_id" => club_id, "id" => id, "item" => item_params}) do
...
end
You’re not using the functions on your route helpers correctly. It doesn’t matter how you implemented your controller actions.
E.g. the @update_attrs
are quite likely supposed to be the third argument for put
nad not the last argument for your path helper.
If I try:
conn = put(conn, Routes.club_item_path(conn, :update, item.club_id, item.id), @update_attrs)
or
conn = put(conn, Routes.club_item_path(conn, :update, item.club_id, item.id), item: @update_attrs)
I still get ArgumentError. Which is weird because this post works:
conn = post(conn, Routes.club_item_path(conn, :create, club.id), item: @create_attrs )
dom
May 19, 2019, 10:10pm
9
The router helper takes a route in your controller like:
post “/api/clubs/:club_id/items”, ItemController, :create
(or a resource, which generates the above)
and provides a function that takes the conn or endpoint, the action (:create), and the :club_id, and returns the correct URL.
It doesn’t make sense to pass an item_id or item attributes to that function, they’re not part of the URL parameters.
If you have a different route like:
put “api/clubs/:club_id/items/:item_id”, ItemController, :update
then you’d pass both the :club_id and :item_id, because the URL has these two parameters.
Try calling h DummyAPIWeb.Router.Helpers.club_item_path
in iex when your app is running, it’ll show you what arguments are expected.
Edit: for the second question, can you please include the full error? ArgumentError on its own is really vague.
iex(1)> h DummyApiWeb.Router.Helpers.club_item_path
def club_item_path(conn_or_endpoint, action, club_id)
def club_item_path(conn_or_endpoint, action, club_id, params)
def club_item_path(conn_or_endpoint, action, club_id, id, params)
The full error is:
** (ArgumentError) argument error
code: conn = delete(conn, Routes.club_item_path(conn, :delete, item.club_id))
stacktrace:
:erlang.apply({:ok, [item: %DummyApi.Items.Item{__meta__: #Ecto.Schema.Metadata<:loaded, "items">, author: "some author", club: #Ecto.Association.NotLoaded<association :club is not loaded>, club_id: 1, comments: #Ecto.Association.NotLoaded<association :comments is not loaded>, id: 1, inserted_at: ~N[2019-05-19 21:36:28],xbn: "some xbn", name: "some name", scheduled_meet_ups: #Ecto.Association.NotLoaded<association :scheduled_meet_ups is not loaded>, updated_at: ~N[2019-05-19 21:36:28], votes: #Ecto.Association.NotLoaded<association :votes is not loaded>}]}, :club_id, [])
test/dummy_api_web/controllers/item_controller_test.exs:97: (test)
dom
May 19, 2019, 11:01pm
11
Are you sure the item
variable really contains an item, and not a tuple like {:ok, item: [...]}
?
2 Likes
That was it. My autogenerated fixture function was returning data in that format
def fixture(:item) do
{:ok, club} = Clubs.create_club(%{description: "some description", name: "some name"})
{:ok, item} = Items.create_item(club, @create_attrs)
end
Thanks a bunch for the help.