phoenix-framework 与复选框的多对多关系在验证失败时引发 argumentError
phoenix-framework many-to-many relationship with checkbox raises argumentError when validation fails
我正在学习 elixir 和 phoenix 框架以及一个具有添加房间形式的应用程序。房间可能与停车位和便利设施有 many-to-many
关系。停车场和便利设施就像通过复选框选中的标签,除了房间有价格、地址、纬度、经度和其他字段。当我填写所有正确的值时,一切都运作良好,并创造了空间。但是抛出
当我检查停车或便利设施字段并将其他字段留空并提交时出现 ArgumentError。
Request: POST /rooms
** (exit) an exception was raised:
** (ArgumentError) lists in Phoenix.HTML and templates may only contain integers representing bytes, binaries or other lists, got invalid entry: #Ecto.Changeset<action: :update, changes: %{}, errors: [], data: #Tailwind.Parkings.Parking<>, valid?: true>
这是验证失败时抛出的变更集。
Ecto.Changeset<
action: nil,
changes: %{
amenities: [
#Ecto.Changeset<action: :update, changes: %{}, errors: [],
data: #Tailwind.Amenities.Amenity<>, valid?: true>
],
parkings: [
#Ecto.Changeset<action: :update, changes: %{}, errors: [],
data: #Tailwind.Parkings.Parking<>, valid?: true>
]
},
errors: [
address: {"can't be blank", [validation: :required]},
price: {"can't be blank", [validation: :required]},
number_of_rooms: {"can't be blank", [validation: :required]},
lat: {"can't be blank", [validation: :required]},
long: {"can't be blank", [validation: :required]}
],
data: #Tailwind.Rooms.Room<>,
valid?: false
>
我最好的猜测是变化中的便利设施和停车位值是问题的原因。便利设施和停车场领域有一个变更集,而不是简单的列表。尽管我的猜测是正确的,但我对它为什么会这样以及它应该如何表现没有足够的理解。
我正在我的上下文中添加与 put_assoc 函数的关联。
def create_room(attrs \ %{}) do
%Room{}
|> Room.changeset(attrs)
|> put_parking_association(attrs["parkings"])
|> put_amenity_association(attrs["amenities"])
|> Repo.insert()
end
和 put_amenity_association 函数只是从数据库中获取具有该 ID 的所有值并添加与它们的关联。
defp put_amenity_association(changeset, attrs) do
amenities = Tailwind.Amenities.get_amenities(attrs)
Ecto.Changeset.put_assoc(changeset, :amenities, amenities)
end
def get_amenities(ids) do
Repo.all(from a in Tailwind.Amenities.Amenity, where: a.id in ^ids)
end
我正在模板中渲染这样的表单。
<%= for amenity <- @amenities do %>
<div class="flex items-center py-2 sm:w-1/4">
<%= checkbox f, :amenities,
checked_value: amenity.id,
hidden_input: false,
name: "room[amenities][]",
class: "h-5 w-5 focus:ring-gray-900 focus:ring-1 bg-gray-900 text-gray-600" %>
<span class="ml-3 text-sm"><%= amenity.name %></span>
<% end %>
<span class="text-red-600 px-2">
<%= error_tag f, :amenities %>
</span>
我纠结了几天,没有任何结果,感到迷茫。对这件事的一点点阳光对前进会有很大的帮助。
更新:
使用可接受的解决方案,我将 create_room 函数更改如下:
def create_room(attrs \ %{}) do
case Room.changeset(%Room{}, attrs) do
%Ecto.Changeset{valid?: false} = changes ->
changes
|> apply_action(:insert)
# |> Repo.insert()
changeset ->
changeset
|> put_parking_association(attrs["parkings"])
|> put_amenity_association(attrs["amenities"])
|> IO.inspect()
|> Repo.insert()
end
end
当缺少必填字段时,Room.changeset(attrs)
returns 一个无效的变更集,不会被任何后续调用进一步修改(因为它已经无效。)
它直接传递给 Repo.insert/2
returns {:error, changeset}
返回。
所以你需要的可能是不仅要处理快乐的路径,还要处理错误。
def create_room(attrs \ %{}) do
case Room.changeset(%Room{}, attrs) do
%Ecto.Changeset{valid?: false} -> handle_error(...)
changeset ->
changeset
|> put_parking_association(attrs["parking"])
|> put_amenity_association(attrs["amenities"])
|> Repo.insert()
end
...
您看到的错误可能是在堆栈的下方引起的,但原因与上述错误并列。
我正在学习 elixir 和 phoenix 框架以及一个具有添加房间形式的应用程序。房间可能与停车位和便利设施有 many-to-many
关系。停车场和便利设施就像通过复选框选中的标签,除了房间有价格、地址、纬度、经度和其他字段。当我填写所有正确的值时,一切都运作良好,并创造了空间。但是抛出
当我检查停车或便利设施字段并将其他字段留空并提交时出现 ArgumentError。
Request: POST /rooms
** (exit) an exception was raised:
** (ArgumentError) lists in Phoenix.HTML and templates may only contain integers representing bytes, binaries or other lists, got invalid entry: #Ecto.Changeset<action: :update, changes: %{}, errors: [], data: #Tailwind.Parkings.Parking<>, valid?: true>
这是验证失败时抛出的变更集。
Ecto.Changeset<
action: nil,
changes: %{
amenities: [
#Ecto.Changeset<action: :update, changes: %{}, errors: [],
data: #Tailwind.Amenities.Amenity<>, valid?: true>
],
parkings: [
#Ecto.Changeset<action: :update, changes: %{}, errors: [],
data: #Tailwind.Parkings.Parking<>, valid?: true>
]
},
errors: [
address: {"can't be blank", [validation: :required]},
price: {"can't be blank", [validation: :required]},
number_of_rooms: {"can't be blank", [validation: :required]},
lat: {"can't be blank", [validation: :required]},
long: {"can't be blank", [validation: :required]}
],
data: #Tailwind.Rooms.Room<>,
valid?: false
>
我最好的猜测是变化中的便利设施和停车位值是问题的原因。便利设施和停车场领域有一个变更集,而不是简单的列表。尽管我的猜测是正确的,但我对它为什么会这样以及它应该如何表现没有足够的理解。
我正在我的上下文中添加与 put_assoc 函数的关联。
def create_room(attrs \ %{}) do
%Room{}
|> Room.changeset(attrs)
|> put_parking_association(attrs["parkings"])
|> put_amenity_association(attrs["amenities"])
|> Repo.insert()
end
和 put_amenity_association 函数只是从数据库中获取具有该 ID 的所有值并添加与它们的关联。
defp put_amenity_association(changeset, attrs) do
amenities = Tailwind.Amenities.get_amenities(attrs)
Ecto.Changeset.put_assoc(changeset, :amenities, amenities)
end
def get_amenities(ids) do
Repo.all(from a in Tailwind.Amenities.Amenity, where: a.id in ^ids)
end
我正在模板中渲染这样的表单。
<%= for amenity <- @amenities do %>
<div class="flex items-center py-2 sm:w-1/4">
<%= checkbox f, :amenities,
checked_value: amenity.id,
hidden_input: false,
name: "room[amenities][]",
class: "h-5 w-5 focus:ring-gray-900 focus:ring-1 bg-gray-900 text-gray-600" %>
<span class="ml-3 text-sm"><%= amenity.name %></span>
<% end %>
<span class="text-red-600 px-2">
<%= error_tag f, :amenities %>
</span>
我纠结了几天,没有任何结果,感到迷茫。对这件事的一点点阳光对前进会有很大的帮助。
更新:
使用可接受的解决方案,我将 create_room 函数更改如下:
def create_room(attrs \ %{}) do
case Room.changeset(%Room{}, attrs) do
%Ecto.Changeset{valid?: false} = changes ->
changes
|> apply_action(:insert)
# |> Repo.insert()
changeset ->
changeset
|> put_parking_association(attrs["parkings"])
|> put_amenity_association(attrs["amenities"])
|> IO.inspect()
|> Repo.insert()
end
end
当缺少必填字段时,Room.changeset(attrs)
returns 一个无效的变更集,不会被任何后续调用进一步修改(因为它已经无效。)
它直接传递给 Repo.insert/2
returns {:error, changeset}
返回。
所以你需要的可能是不仅要处理快乐的路径,还要处理错误。
def create_room(attrs \ %{}) do
case Room.changeset(%Room{}, attrs) do
%Ecto.Changeset{valid?: false} -> handle_error(...)
changeset ->
changeset
|> put_parking_association(attrs["parking"])
|> put_amenity_association(attrs["amenities"])
|> Repo.insert()
end
...
您看到的错误可能是在堆栈的下方引起的,但原因与上述错误并列。