凤凰丹药 Post JSON 有关联

Phoenix Elixir Post JSON with association

我想 POST 与 Phoenix Elixir 中的 JSON 进行一对多关联。网上有很多例子,但是我还没有看到一个一对多关联的例子。如何在控制器中传递联系人参数?

Costumer 的架构是

schema "customers" do
  field :email, :string
  field :name, :string
  has_many :contacts, App.Customers.Contact

  timestamps()
end

@doc false
def changeset(customer, attrs \ %{}) do
  customer
  |> cast(attrs, [:name, :email])
  |> validate_required([:name, :email])
  |> unique_constraint(:email)
end

Contact 的架构是

schema "contacts" do
  field :phone, :string
  belongs_to :customers, App.Customers.Customer,  foreign_key: :customer_id

  timestamps()
end

@doc false
def changeset(contact, attrs \ %{}) do
  contact
  |> cast(attrs, [:phone])
  |> validate_required([:phone])
end

这是控制器:

def create(conn, %{"email" => email, "name" => name, "phone" => phone} = customer_params) do
  with {:ok, %Customer{} = customer} <- Customers.create_customer(customer_params) do
    conn
    |> put_status(:created)
    |> put_resp_header("location", Routes.customer_path(conn, :show, customer))
    |> render("show.json", customer: customer)
  end
end

Customer中,将changeset函数改为:

def changeset(customer, attrs \ %{}) do
  customer
  |> cast(attrs, [:name, :email])
  |> validate_required([:name, :email])
  |> unique_constraint(:email)
  |> cast_assoc(:contacts)
end

然后像这样传递参数:

%{"name" => "john doe", "email" => "example@example.com", "contacts" => [
  %{"phone" => "555-555-555"},
  %{"phone" => "555-555-555"}
]}

有了这个,上下文中的create_customer函数就不需要改变了:

def create_customer(attrs \ %{}) do
  %Customer{}
  |> Customer.changeset(attrs)
  |> Repo.insert()
end

不过请记住,要更新 Customer,您需要先预加载联系人。

您可以在 cast_assoc documentation 中找到更多信息。