Hi all
I have a video controller that looks as follow:
defmodule Rumbl.VideoController do
use Rumbl.Web, :controller
alias Rumbl.Video
alias Rumbl.Category
plug :load_categories when action in [:new, :create, :edit, :update]
defp load_categories(conn, _) do
query =
Category
|> Category.alphabetical
|> Category.names_and_ids
categories = Repo.all query
assign(conn, :categories, categories)
end
def action(conn, _) do
apply(__MODULE__, action_name(conn),
[conn, conn.params, conn.assigns.current_user])
end
def index(conn, _params, user) do
videos = Repo.all(user_videos(user))
render(conn, "index.html", videos: videos)
end
def show(conn, %{"id" => id}, user) do
video = Repo.get!(user_videos(user), id)
render(conn, "show.html", video: video)
end
def new(conn, _params, user) do
changeset =
user
|> build_assoc(:videos)
|> Video.changeset()
render(conn, "new.html", changeset: changeset)
end
def create(conn, %{"video" => video_params}, user) do
changeset =
user
|> build_assoc(:videos)
|> Video.changeset(video_params)
case Repo.insert(changeset) do
{:ok, _video} ->
conn
|> put_flash(:info, "Video created successfully.")
|> redirect(to: video_path(conn, :index))
{:error, changeset} ->
render(conn, "new.html", changeset: changeset)
end
end
def edit(conn, %{"id" => id}, user) do
video = Repo.get!(user_videos(user), id)
changeset = Video.changeset(video)
render(conn, "edit.html", video: video, changeset: changeset)
end
def update(conn, %{"id" => id, "video" => video_params}, user) do
video = Repo.get!(user_videos(user), id)
changeset = Video.changeset(video, video_params)
case Repo.update(changeset) do
{:ok, video} ->
conn
|> put_flash(:info, "Video updated successfully.")
|> redirect(to: video_path(conn, :show, video))
{:error, changeset} ->
render(conn, "edit.html", video: video, changeset: changeset)
end
end
def delete(conn, %{"id" => id}, user) do
video = Repo.get!(user_videos(user), id)
Repo.delete!(video)
conn
|> put_flash(:info, "Video deleted successfully.")
|> redirect(to: video_path(conn, :index))
end
defp user_videos(user) do
assoc(user, :videos)
end
end
Then I wrote a test for controller
defmodule Rumbl.VideoControllerTest do
use Rumbl.ConnCase
test "requires user authentication on all actions", %{conn: conn} do
Enum.each([
get(conn, video_path(conn, :new)),
get(conn, video_path(conn, :index)),
get(conn, video_path(conn, :show, "123")),
get(conn, video_path(conn, :edit, "123")),
put(conn, video_path(conn, :update, "123", %{})),
post(conn, video_path(conn, :create, %{})),
delete(conn, video_path(conn, :delete, "123")),
], fn conn ->
assert html_response(conn, 302)
assert conn.halted
end)
end
end
and try to test it, but I’ve got error message
1) test requires user authentication on all actions (Rumbl.VideoControllerTest)
test/controllers/video_controller_test.exs:4
** (FunctionClauseError) no function clause matching in Ecto.build_assoc/3
stacktrace:
(ecto) lib/ecto.ex:460: Ecto.build_assoc(nil, :videos, %{})
(rumbl) web/controllers/video_controller.ex:40: Rumbl.VideoController.new/3
(rumbl) web/controllers/video_controller.ex:1: Rumbl.VideoController.action/2
(rumbl) web/controllers/video_controller.ex:1: Rumbl.VideoController.phoenix_controller_pipeline/2
(rumbl) lib/rumbl/endpoint.ex:1: Rumbl.Endpoint.instrument/4
(rumbl) lib/phoenix/router.ex:261: Rumbl.Router.dispatch/2
(rumbl) web/router.ex:1: Rumbl.Router.do_call/2
(rumbl) lib/rumbl/endpoint.ex:1: Rumbl.Endpoint.phoenix_pipeline/1
(rumbl) lib/rumbl/endpoint.ex:1: Rumbl.Endpoint.call/2
(phoenix) lib/phoenix/test/conn_test.ex:224: Phoenix.ConnTest.dispatch/5
test/controllers/video_controller_test.exs:6: (test)
.....
Finished in 0.1 seconds
9 tests, 1 failure
I could not find out, what is wrong with new function.
Thanks