使用 embeds_many 时删除空的嵌套表单
Removing empty nested form when using embeds_many
我有一个嵌套表单,其中只需要提供的 1/5 选项。但是,如果用户提交的表单仅填写了 1 个嵌套表单,则 Ecto returns 变更集无效。
我在我的控制器中添加了一个 scrub_params
插件,但它似乎并没有删除空的嵌套表单。
plug(:scrub_params, "inventories" when action in [:create])
Phoenix 有没有办法去除空表格?
连接参数参数["inventories"]:
%{"payment_invoice_type" => "mail",
"delivery_methods" =>
%{"0" => %{"cost" => "10.00", "description" => "Del Option 1"},
"1" => %{"cost" => "20.00", "description" => "Del Option 2"},
"2" => %{"cost" => "30.00", "description" => "Del Option 3"},
"3" => %{"cost" => nil, "description" => nil}, # should be discarded
"4" => %{"cost" => nil, "description" => nil}}, # should be discarded
"payment_method" => "cash",
}
变更集结果:
#Ecto.Changeset<action: nil,
changes: %{payment_invoice_type: "mail,
delivery_methods: [#Ecto.Changeset<action: :insert,
changes: %{cost: #Decimal<10.00>, description: "Del Option 1"}, errors: [],
data: #Book.Store.ShippingMethod<>, valid?: true>,
#Ecto.Changeset<action: :insert,
changes: %{cost: #Decimal<20.00>, description: "Del Option 2"}, errors: [],
data: #Book.Store.ShippingMethod<>, valid?: true>,
#Ecto.Changeset<action: :insert,
changes: %{cost: #Decimal<30.00>, description: "Del Option 3"}, errors: [],
data: #Book.Store.ShippingMethod<>, valid?: true>,
#Ecto.Changeset<action: :insert, changes: %{},
errors: [description: {"can't be blank", [validation: :required]},
cost: {"can't be blank", [validation: :required]}],
data: #Book.Store.ShippingMethod<>, valid?: false>,
#Ecto.Changeset<action: :insert, changes: %{},
errors: [description: {"can't be blank", [validation: :required]},
cost: {"can't be blank", [validation: :required]}],
data: #Book.Store.ShippingMethod<>, valid?: false>],
payment_method: "cash"},
errors: [],
data: #Book.Store.Inventory<>, valid?: false>
父架构:
schema "inventories" do
field :payment_invoice_type, :string
field :payment_method, :string
embeds_many :shipping_options, Book.Store.ShippingOptions
timestamps()
end
父变更集:
def changeset(%Inventory{} = inventory, attrs) do
inventory
|> cast(attrs, [:payment_invoice_type, :payment_method])
|> validate_required([:payment_invoice_type, :payment_method])
|> cast_embed(:shipping_methods, required: true)
end
嵌入式架构:
@primary_key false
embedded_schema do
field :description, :string
field :cost, :decimal
end
def changeset(%DeliveryOption{} = delivery_option, attrs) do
delivery_option
|> cast(attrs, [:description, :cost])
|> validate_required([:description, :cost])
|> validate_length(:description, min: 5, max: 75)
end
我认为在 Ecto 中没有自动删除此类条目的方法。您可以像这样轻松地手动删除条目:
inventories = Map.update!(inventories, "delivery_methods", fn map ->
:maps.filter(fn _key, value -> !match?(%{"cost" => nil, "description" => nil}, value), map)
end)
这将删除所有 delivery_methods
值,其中 cost
和 description
都设置为 nil
。
或者,以下将删除所有值都设置为 nil 的条目:
inventories = Map.update!(inventories, "delivery_methods", fn map ->
map |> Map.values |> Enum.all?(&is_nil/1)
end)
我有一个嵌套表单,其中只需要提供的 1/5 选项。但是,如果用户提交的表单仅填写了 1 个嵌套表单,则 Ecto returns 变更集无效。
我在我的控制器中添加了一个 scrub_params
插件,但它似乎并没有删除空的嵌套表单。
plug(:scrub_params, "inventories" when action in [:create])
Phoenix 有没有办法去除空表格?
连接参数参数["inventories"]:
%{"payment_invoice_type" => "mail",
"delivery_methods" =>
%{"0" => %{"cost" => "10.00", "description" => "Del Option 1"},
"1" => %{"cost" => "20.00", "description" => "Del Option 2"},
"2" => %{"cost" => "30.00", "description" => "Del Option 3"},
"3" => %{"cost" => nil, "description" => nil}, # should be discarded
"4" => %{"cost" => nil, "description" => nil}}, # should be discarded
"payment_method" => "cash",
}
变更集结果:
#Ecto.Changeset<action: nil,
changes: %{payment_invoice_type: "mail,
delivery_methods: [#Ecto.Changeset<action: :insert,
changes: %{cost: #Decimal<10.00>, description: "Del Option 1"}, errors: [],
data: #Book.Store.ShippingMethod<>, valid?: true>,
#Ecto.Changeset<action: :insert,
changes: %{cost: #Decimal<20.00>, description: "Del Option 2"}, errors: [],
data: #Book.Store.ShippingMethod<>, valid?: true>,
#Ecto.Changeset<action: :insert,
changes: %{cost: #Decimal<30.00>, description: "Del Option 3"}, errors: [],
data: #Book.Store.ShippingMethod<>, valid?: true>,
#Ecto.Changeset<action: :insert, changes: %{},
errors: [description: {"can't be blank", [validation: :required]},
cost: {"can't be blank", [validation: :required]}],
data: #Book.Store.ShippingMethod<>, valid?: false>,
#Ecto.Changeset<action: :insert, changes: %{},
errors: [description: {"can't be blank", [validation: :required]},
cost: {"can't be blank", [validation: :required]}],
data: #Book.Store.ShippingMethod<>, valid?: false>],
payment_method: "cash"},
errors: [],
data: #Book.Store.Inventory<>, valid?: false>
父架构:
schema "inventories" do
field :payment_invoice_type, :string
field :payment_method, :string
embeds_many :shipping_options, Book.Store.ShippingOptions
timestamps()
end
父变更集:
def changeset(%Inventory{} = inventory, attrs) do
inventory
|> cast(attrs, [:payment_invoice_type, :payment_method])
|> validate_required([:payment_invoice_type, :payment_method])
|> cast_embed(:shipping_methods, required: true)
end
嵌入式架构:
@primary_key false
embedded_schema do
field :description, :string
field :cost, :decimal
end
def changeset(%DeliveryOption{} = delivery_option, attrs) do
delivery_option
|> cast(attrs, [:description, :cost])
|> validate_required([:description, :cost])
|> validate_length(:description, min: 5, max: 75)
end
我认为在 Ecto 中没有自动删除此类条目的方法。您可以像这样轻松地手动删除条目:
inventories = Map.update!(inventories, "delivery_methods", fn map ->
:maps.filter(fn _key, value -> !match?(%{"cost" => nil, "description" => nil}, value), map)
end)
这将删除所有 delivery_methods
值,其中 cost
和 description
都设置为 nil
。
或者,以下将删除所有值都设置为 nil 的条目:
inventories = Map.update!(inventories, "delivery_methods", fn map ->
map |> Map.values |> Enum.all?(&is_nil/1)
end)