Routing - How do I create nested subdirectories?

I’m not sure if the title explains what I’m trying to do well. So here’s some context:

I have a tests table, and I also have a questions table.

A test has many questions, and a question belongs to a test.

Here is a simplified version of the tables:

tests table

id test_name
1 Java Test

questions table

id question_number question_title options correct_answer test_id
1 1 What is an integer? [“a”, “b” “2”] “2” 1

Now what I am trying to achieve is:

I want users to be able to go to /my-tests directory which will display all tests with buttons to take the test. Once a button is pressed for a particular test (i.e id: 1), I want the first question to load for that test based on question_number. I will then want Next and Back buttons to cycle through all questions in the test.

Now as far as routing goes, I managed to get to the point where I display all tests for a user under the /my-tests directory.

I did this by adding resources("/my-tests", StudentTestController) to my router.ex file. The index page shows all tests, each test has a link called “Take Test” which routes to:
<%= link "Take Test", to: Routes.student_test_path(@conn, :show, test) %>

The show function looks like this:

def show(conn, %{"id" => id}) do
  test = Tests.get_test!(id)
  render(conn, "show.html", test: test)

By doing this, when I click “Take Test” on a particular test (i.e id: 1), I would get directed here:
/my-tests/1 which would be the show.html.heex in the student_test_path.

But actually, I want it to direct me to /my-tests/1?question=1. The show.html.heex should then have buttons which cycle between the questions.

How would I achieve this?

You can add question_id to route along with id. Your existing path to test should stay as is.

Path will be /my-tests/1/questions/1 - then in your show

def show(conn, %{“id” => id, “question_id” => question_id) do

Test taker will come to /my-tests/1 then question is rendered by redirecting to /my-tests/1/questions/1 to end of tests

If you want to access query params - they will be in conn param of show function - Plug.Conn — Plug v1.12.1

1 Like

This is very helpful, I did something similar:

<%= link "Take Test", to: Routes.student_test_path(@conn, :show, test, %{"question" => 1}) %>

In the index.html.heex I pass in a 1 rather than the question_id. This is because I will always want the test to start with the first question. I can get all the necessary question params with a query that checks the test_id and current question_number.

I then added a next and back button in the show.html.heex like so:

<%= link "Next", to: Routes.student_test_path(@conn, :show, @test, %{"question" => @question_number + 1}), class: "button" %>
<%= if @question_number > 1 do %>
    <%= link "Back", to: Routes.student_test_path(@conn, :show, @test, %{"question" => @question_number - 1}) %>
<% end %>

Now when I click “Take Test” in the index.html I get exactly what I want:
Clicking the “Next” button increases the question number by 1 and “Back” subtracts it by 1.

I have another issue but it isn’t very related to this so I’ll make another thread.

1 Like