【问题标题】:Show queried data from Phoenix controller in eex template在 eex 模板中显示来自 Phoenix 控制器的查询数据
【发布时间】:2026-02-10 23:35:02
【问题描述】:

我在 Phoenix 控制器中有一个查询,它获取一个学生列表,并且对于列表中的每一行,都会在其 id 上与血型进行连接并获取血型名称。我想在我生成但出现错误的 eex 模板中显示它。

这是学生模式:

schema "students" do
  field :firstname, :string
  field :lastname, :string
  field :birthday, Ecto.Date
  field :joined_on, Ecto.Date
  field :bloodgroup_id, :integer

  timestamps()
end

这是血型模型:

schema "bloodgroups" do
  field :name, :string
  timestamps()
end

我正在像这样在控制器中获取数据:

def query do
  query =  from s in Student,
        join: b in BloodGroup, on: s.bloodgroup_id == b.id,
        select: [s.firstname, s.lastname, s.birthday, s.joined_on, s.bloodgroup_id, b.name]
end

def index(conn, _params) do
  students = Repo.all(query)
  render(conn, "index.html", student_info: students)
end

并像这样在模板中显示:

<%= for student <- @student_info do %>
<tr>
  <td><%= Enum.fetch(student, 0) %></td>
  <td><%= student[:lastname] %></td>
  <td><%= student[:birthday] %></td>
  <td><%= student[:joined_on] %></td>
  <td><%= student[:name] %></td>

  <td class="text-right">
    <%= link "Show", to: student_path(@conn, :show, student), class: "btn btn-default btn-xs" %>
    <%= link "Edit", to: student_path(@conn, :edit, student), class: "btn btn-default btn-xs" %>
    <%= link "Delete", to: student_path(@conn, :delete, student), method: :delete, data: [confirm: "Are you sure?"], class: "btn btn-danger btn-xs" %>
  </td>
</tr>
<% end %>

但是使用Enum.fetchstudent[:firstname] 的形式不起作用并抛出Argument errorprotocol Phoenix.HTML.Safe not implemented

我想在模板中显示从控制器发送的内容,但遇到了这些错误。有一个更好的方法吗?我是 Phoenix 和 Elixir 的新手。

【问题讨论】:

    标签: elixir phoenix-framework ecto


    【解决方案1】:

    根据您发布的查询,您应该会返回带有Repo.all 的列表列表。您可以使用模式匹配来提取数据,例如:

    <%= for [firstname, lastname, birthday, joined_on, bloodgroup_id, name] <- @student_info do %>
    

    但是,这不是惯用的。你真的应该在这里使用 Ecto 的关系。

    BloodGroup 添加为belongs_toStudent 的关系:

    schema "students" do
      ...
      belongs_to :bloodgroup, BloodGroup, foreign_key: :bloodgroup_id
    end
    

    然后像这样进行查询:

    students = Repo.all(Student) |> Repo.preload(:bloodgroup)
    

    那么你的模板就变成了:

    <%= for student <- @student_info do %>
      <tr>
        <td><%= student.lastname %></td>
        <td><%= student.birthday %></td>
        <td><%= student.joined_on %></td>
        <td><%= student.bloodgroup.name %></td>
    
        <td class="text-right">
          <%= link "Show", to: student_path(@conn, :show, student), class: "btn btn-default btn-xs" %>
          <%= link "Edit", to: student_path(@conn, :edit, student), class: "btn btn-default btn-xs" %>
          <%= link "Delete", to: student_path(@conn, :delete, student), method: :delete, data: [confirm: "Are you sure?"], class: "btn   btn-danger btn-xs" %>
        </td>
      </tr>
    <% end %>
    

    所有代码都未经测试。如果这不起作用,请告诉我。这可能是某个地方的错字。

    【讨论】:

    • 谢谢!我采用惯用的方式并使用了更容易的关系。虽然我在使用上面的belongs_to 时遇到了错误。经过一些研究,我使用了以下内容并且它有效:belongs_to :bloodgroup, BloodGroup, foreign_key: :bloodgroup_id