#elixir #phoenix-framework #ecto
#elixir #phoenix-framework #ecto
Вопрос:
Я новичок в Phoenix и Elixir, но я очень стараюсь его изучить. Это может быть глупо простой вопрос, но я не знаю, как отобразить полное имя автора книги на странице index / show книги.
Вот мой запрос в inventory / book.ex
def get_author_full_name(author) do
from b in "books",
join: a in "authors",
on: b.author_id == a.id,
where: a.id == ^author,
select: %{id: a.id, name: concat(a.first_name, ' ', a.last_name)}
end
Пользовательский SQL:
defmodule CustomSQLFunctions do
defmacro concat(left, mid, right) do
quote do
fragment("concat(?, ?, ?)", unquote(left), unquote(mid), unquote(right))
end
end
end
И в inventory.ex
def display_author_full_name do
Author
|> Author.get_author_full_name()
|> Repo.all()
end
В book_controller.ex
plug :load_author_full_name when action in [:index, :show]
defp load_author_full_name(conn, _) do
assign(conn, :books, Bookstore.Inventory.display_author_full_name ())
end
Я следовал инструкциям из книги Programming Phoenix 1.4, чтобы отобразить выпадающий список категорий с некоторыми небольшими изменениями в соответствии с моим случаем. Может кто-нибудь подсказать мне, как отобразить полное имя автора книги? Я не знаю, написал ли я соответствующий код обращения и что поместить на страницы просмотра и индексирования / показа.
Комментарии:
1. Просто чтобы уточнить: есть ли причина, по которой вы не хотите использовать отдельные переменные для имени и фамилии? Другими словами, почему бы просто не выполнить «конкатенацию» на уровне представления?
2. Также… Меня смущает ваша
get_author_full_name/1
функция… Я не понимаю, почему вы присоединяетесь кbooks
таблице, когда все, что вы хотите получить, это имя автора — я не думаю, что требуется какое-либо объединение. Имя функции вводит в заблуждение: вы извлекаете список авторов (или, возможно, список авторов, объединенных с данными книги). Вы могли бы просто положиться наpreload
опцию, чтобы избежать проблемы N 1 — предполагая, что у вас есть схемы дляBook
иAuthor
, это может выглядеть такfrom(b in Book, preload: [:authors]) |> Repo.all()
3. Спасибо за ваш ответ! Я новичок в elixir и phoenix, и я подумал, что было бы неплохо сделать что-то «похожее» на то, что есть в книге. Я придумал что-то вроде:
<% fullname = book.author.first_name <> " " <> book.author.last_name %>
в index / show.html.eex, а затем:<td><%= fullname %></td>
. Но я думаю, это не идеальное решение.4. Здорово пробовать — вот как ты учишься! В этом случае вы также могли бы сделать
<td><%= book.author.first_name %> <%= book.author.last_name %></td>
. Однако будут случаи, когда вам нужно будет где-то применить некоторую бизнес-логику, чтобы последовательно изменять данные, прежде чем использовать их в представлении (например, что-то более сложное, чем конкатенация). Часто для этого используется выделенный модуль или функция — некоторые языки делают подобные вещи в «классах обслуживания»; Phoenix использует «контексты» как место, где такие манипуляции могут происходить до отправки данных в представление.5. Я серьезно отнесся к вашему вопросу и попробовал закодировать его в представлении. Вот результат. У
book_view.ex
меня есть:def full_name(%Writers.Author{first_name: first_name, last_name: last_name}) do [first_name, last_name] |> Enum.reject(amp;(amp;1 == "")) |> Enum.join(" ") end
и в index.html.eex:<td><%= full_name(book.author) %></td>