
API - Add talks to agenda
(Use git checkout 8.agenda
to catch up with the class)
We need a way for user to add a talk to their agenda. Run this command to generate a user talk relationship.
mix phx.gen.json Agenda UserTalk users_talks user_id:references:users talk_id:references:talks
Open up lib/fawkes/agenda/user_talk.ex
. Add :user_id
and :talk_id
to the cast so your changeset will look like this:
def changeset(user_talk, attrs) do
user_talk
|> cast(attrs, [:user_id, :talk_id])
|> validate_required([])
end
In the router
, add an api scope for user_talk
:
scope "/api", FawkesWeb do
pipe_through [:api]
resources "/users_talks", UserTalkController, except: [:new, :edit]
end
Open up the lib/fawkes_web/controller/user_talk_controller.ex
, and don’t match the param. Change the param to user_talk_params
, like this:
def create(conn, user_talk_params) do
with {:ok, %UserTalk{} = user_talk} <- Agenda.create_user_talk(user_talk_params) do
conn
|> put_status(:created)
|> put_resp_header("location", user_talk_path(conn, :show, user_talk))
|> render("show.json", user_talk: user_talk)
end
end
Run the migration to create the table:
mix ecto.migrate
Now we’re ready to save! Go to http://localhost:4000/schedule_slots, click add to agenda on a few slot. We added the javascript to handle the add. If you open up your console, you can see the JSON the server sends.
Showing my agenda
(Use git checkout 8a.show_agenda
to catch up with the class)
Let’s get our agendas. In your router
, below resources "/speakers", SpeakerController
, add a path to retrieve your agenda
get "/agenda", AgendaController, :index
When the user hits this endpoint, we will retrieve all the talks for the current user. Let’s create a new controller called lib/fawkes_web/controller/agenda_controller.ex
. Add this code:
defmodule FawkesWeb.AgendaController do
use FawkesWeb, :controller
alias Fawkes.Agenda
def index(conn, _params) do
talks = Agenda.list_talk_for_user(conn.assigns.current_user.id)
render(conn, "index.html", talks: talks)
end
end
Open lib/fawkes/agenda/agenda.ex
, add in this function to retrieve the talks:
alias Fawkes.Schedule.Talk
def list_talk_for_user(user_id) do
Talk
|> preload([:slot, :speakers, :categories, :audience, :location])
|> join(:inner, [talk], user_talk in UserTalk, user_talk.talk_id == talk.id and user_talk.user_id == ^user_id)
|> Repo.all()
end
Now that we retrieved the talk, let’s display it. Create a new file called lib/fawkes_web/views/agenda_view.ex
. Add this code to render the view:
defmodule FawkesWeb.AgendaView do
use FawkesWeb, :view
end
Now let’s get the HTML for the view. Create a new folder called lib/fawkes_web/templates/agenda
. Create a new file called lib/fawkes_web/templates/agenda/index.html.eex
. Add this code to display the data:
<div class="talk-index">
<div class="section-white">
<div class="container">
<div class="d-flex justify-content-center align-items-center dates">
<i class="fas fa-arrow-left"></i>
<%= for {day_number, day_name} <- [{4, "Tue"}, {5, "Wed"}, {6, "Thu"}, {7, "Fri"}] do %>
<div class="card">
<div class="card-body">
<div class="dates__name smalltext"><%= day_name %></div>
<div class="dates__number"><%= day_number %></div>
</div>
</div>
<% end %>
<i class="fas fa-arrow-right"></i>
</div>
<div class="d-flex justify-content-center talk-index__tab">
<a href="/schedule_slots" class="talk-tab__link"><h4 class="subheader">Full Schedule</h4></a>
<a href="/agenda" class="talk-tab__link talk-tab__link-active"><h4 class="subheader">My Agenda</h4></a>
</div>
</div>
</div>
<div class="container schedule">
<%= for talk <- @talks do %>
<div class="card">
<div class="card-body">
<div class="float-right schedule__talk-link"><i class="fas fa-angle-right"></i></div>
<h4 class="subheader"><%= Timex.format!(talk.slot.start_time, "%-I:%M %p", :strftime)%> - <%= Timex.format!(talk.slot.end_time, "%-I:%M %p", :strftime) %></h4>
<a href="/talks/<%= talk.id %>"><h3 class="schedule__talk-title"><%= talk.title %></h3></a>
<div class="schedule__details"><%= FawkesWeb.SharedView.full_name(talk.speakers) %> | <%= talk.location.name %></div>
<p class="icons">
<button class="btn talk__audience"><%= talk.audience.name %></button>
<%= for category <- talk.categories do %>
<%= if category.icon_url do %>
<img src="<%= category.icon_url %>">
<% else %>
<button class="btn talk__category">
<%= category.name %>
</button>
<% end %>
<% end %>
</p>
</div>
</div>
<% end %>
</div>
</div>
Go to http://localhost:4000/agendas. Note the talks you added are there.
Exercise: View other user agenda
(Use git checkout 8b.others_agenda
to catch up with the class)
- Add a new endpoint
/agenda/:user_slug
- Add a new function in the
lib/fawkes_web/controller/agenda_controller.ex
- First find the profile with the given slug
- Find all the talks the user added to their profile given the user_id in the profile
- Since you’re only displaying the talk, you can reuse the index template
render(conn, "index.html", talks: talks)