【问题标题】:Elixir/Phoenix add a. related entity to an existing one via formElixir/Phoenix 添加一个。通过表单与现有实体相关联
【发布时间】:2021-01-02 06:50:35
【问题描述】:

我对 elixir/phoenix 很陌生,而且我在一个概念上有点挣扎。我找到了解决方法,但我对此并不满意。

上下文: 我在我的数据库中创建了一个“项目”。现在我想通过项目“显示”页面创建一个与项目相关的“工作项”。由于它与该特定项目相关,因此我需要将 ID 添加到变更集。

我尝试在projects_controller 中这样做:

def show(conn, %{"id" => id}) do
    project   = Clients.get_project!(id)
    changeset = Clients.change_work_item(%BudgetItem{project_id: project.id})
    render(conn, "show.html", project: project, changeset: changeset)
  end

这是表格:

%= form_for @changeset, @action, fn f -> %>
  <%= if @changeset.action do %>
    <div class="alert alert-danger">
      <p>Oops, something went wrong! Please check the errors below.</p>
    </div>
  <% end %>

  <%= label f, :title %>
  <%= text_input f, :title %>
  <%= error_tag f, :title %>

  <%= label f, "duration" %>
  <%= number_input f, :amount_in_cents %>
  <%= error_tag f, :amount_in_cents %>

  <div>
    <%= submit "Save" %>
  </div>
<% end %>

当我点击提交时,project_id 不在我的 work_item_controller 中的变更集中 - 我的理解是这是因为 elixir 中数据的不变性。我的解决方法是现在我在“存储”project_id (&lt;%= hidden_input f, :project_id %&gt;) 的视图中有一个隐藏字段。这行得通,但我对此不满意,因为用户可以干预它并且很好 - “滥用”视图来执行此操作感觉是错误的。你们中的任何人都可以向我解释这通常是如何完成的吗?我一直找不到令人满意的解决方案。

如果您需要更多代码来更好地理解实现,请告诉我。

感谢您的宝贵时间!

编辑:

defmodule SthWeb.WorkItemController do
  use SthWeb, :controller

  alias Sth.Clients
  alias Sth.Clients.Project

  def create(conn, %{"work_item" => work_item_params}) do
    case Clients.create_work_item(work_item_params) do
      {:ok, work_item} ->
        conn
        |> put_flash(:info, "Budget increased successfully!")
        |> redirect(to: Routes.project_path(conn, :show, work_item.project_id))
      {:error, changeset} ->
        conn
        |> put_flash(:info, "Something went wrong.")
        |> redirect(to: Routes.project_path(conn, :show, 1))
    end
  end
end

【问题讨论】:

    标签: elixir phoenix-framework ecto


    【解决方案1】:

    我认为你有很好的设置来处理你的情况。 您的 project_id 来自用户所在的路径,在您的控制器中,您只需在数据库中找到该项目的存在。所有这些看起来都不错。 但问题是您的show,您不需要此代码changeset = Clients.change_work_item(%BudgetItem{project_id: project.id}),只需使用您的BudgetItem 呈现变更集,如下所示:changeset = Clients.change_work(%BudgetItem{})。现在,在与此相关的控制器的发布操作上,您可以使用发送到控制器的 id 来查找项目并使用 build_assoc 创建关联的工作项。如果您可以在 post 控制器和 Clients 上下文中发送您的代码,它可能会更容易提供帮助。

    【讨论】:

    • 感谢@franck 的回答 - 我也添加了控制器。问题是 - 这是一个不同的控制器work_item_controller 显示在projects_controller 中。我一辈子都不知道从哪里获得项目 ID - 请赐教,我快疯了 :)
    • 控制器的编辑看起来不错。现在您还必须在 work_item_controller 中获取项目的 ID。 def create(conn, %{"id" =&gt; project_id, "work_item" =&gt; work_item_params})。然后,您可以使用您的 Clients.get_project!(project_id) 获取该项目。最后将项目发送至Clients.create_work_item(project, work_item_params)。在函数中,您可以使用put_assoc 分配工作项。希望对你有帮助
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-10
    • 1970-01-01
    • 1970-01-01
    • 2018-06-17
    • 1970-01-01
    相关资源
    最近更新 更多