我正在使用 Elixir 和 Phoenix。我有一个带有文本输入的表单,最多只允许 255 个字符的文本。但是,错误没有显示,我不明白为什么它没有显示错误。唯一的问题是,当数据库或 ecto 尝试插入它时,它会拒绝它并显示错误闪存消息。但我预计验证步骤会显示错误消息。
.input、.modal、...是默认的核心组件。
我还注意到 assigns.wasm_form.source.errors 不为空,但 assigns.wasm_for.errors 为空。
我的相关实时查看代码:
defmodule BotLeagueBackendWeb.ProfileLive do
use BotLeagueBackendWeb, :live_view
alias BotLeagueBackend.Wasm
alias BotLeagueBackend.WasmService
@impl true
def mount(_params, session, socket) do
user_id = session["id"]
socket = socket
|> assign(:conn, %{request_path: "/profile", assigns: %{user: user_id}})
if connected?(socket) do
wasm_form =
%Wasm{}
|> Wasm.changeset(%{})
|> to_form(as: "wasm_form")
uploaded_wasm_modules = WasmService.get_wasm_modules_for_user(user_id)
socket =
socket
|> assign(:wasm_form, wasm_form)
|> allow_upload(:wasm_module, max_entries: 1, max_file_size: 16_000_000, accept: ~w(.wasm))
|> stream(:uploaded_wasm_modules, uploaded_wasm_modules)
{:ok, socket}
else
{:ok, assign(socket, loading: true)}
end
end
@impl true
def render(%{loading: true} = assigns) do
~H"""
<p>Loading...</p>
"""
end
@impl true
def render(assigns) do
~H"""
<.button type="button" phx-click={show_modal("upload-wasm-module-modal")}>
Upload New Bot Version
</.button>
<.modal id="upload-wasm-module-modal">
<.simple_form for={@wasm_form} phx-change="validate" phx-submit="upload" phx-feedback-for="wasm_form">
<%= for entry <- @uploads.wasm_module.entries do %>
<%= for err <- upload_errors(@uploads.wasm_module, entry) do %>
<p class="text-base text-red-500">
<%= error_to_string(err) %>
</p>
<% end %>
<% end %>
<.live_file_input upload={@uploads.wasm_module} required />
<.input
field={@wasm_form[:name]}
type="text"
label="Enter a name for your bot's current version"
required
/>
<.button type="submit" phx-disable-with="Saving...">Upload</.button>
</.simple_form>
</.modal>
<div class="mt-8 max-w-screen-md">
<h4 class="font-semibold mb-4">Uploaded Bot Versions</h4>
<table class="min-w-full">
<thead>
<tr>
<th class="px-6 py-3 border-b-2 border-gray-300 text-left uppercase">Name</th>
<th class="px-6 py-3 border-b-2 border-gray-300 text-left uppercase">Active</th>
<th class="px-6 py-3 border-b-2 border-gray-300 text-left uppercase">MD5</th>
</tr>
</thead>
<tbody id="uploaded_wasm_modules_stream" phx-update="stream">
<tr :for={{dom_id, uploaded_wasm_module} <- @streams.uploaded_wasm_modules} id={dom_id} class="border-t border-gray-300">
<td class="px-6 py-4 whitespace-no-wrap"><%= uploaded_wasm_module.name %></td>
<td class="px-6 py-4 whitespace-no-wrap"><%= uploaded_wasm_module.active %></td>
<td class="px-6 py-4 whitespace-no-wrap"><%= uploaded_wasm_module.md5_hash %></td>
</tr>
</tbody>
</table>
</div>
"""
end
@impl true
def handle_event("upload", %{"wasm_form" => wasm_params}, socket) do
%{user: user_id} = socket.assigns.conn.assigns
# TODO consume_file and saving it should be done in WasmService
{file_path, md5_hash} = List.first(consume_file(socket))
case WasmService.add_wasm_module_for_user(
file_path: file_path,
md5_hash: md5_hash,
name: wasm_params["name"],
user_id: user_id
) do
{:ok, _wasm} ->
socket =
socket
|> put_flash(:info, "Wasm module uploaded successfully")
|> push_navigate(to: ~p"/profile")
{:noreply, socket}
{:error, %Ecto.Changeset{} = changeset} ->
socket =
socket
|> put_flash(:error, "Some error occurred")
|> push_navigate(to: ~p"/profile")
{:noreply, socket}
end
end
@impl true
def handle_event("validate", %{"wasm_form" => params}, socket) do
wasm_form =
%Wasm{}
|> Wasm.changeset(params)
|> to_form(as: "wasm_form")
{:noreply, assign(socket, wasm_form: wasm_form)}
end
defp consume_file(socket) do
consume_uploaded_entries(socket, :wasm_module, fn %{path: path}, _entry ->
file_id = Ecto.UUID.generate()
dest =
Path.join([
:code.priv_dir(:bot_league_backend),
"static",
"uploads",
file_id <> ".wasm"
])
File.cp!(path, dest)
md5_hash = File.stream!(dest,[],2048)
|> Enum.reduce(:crypto.hash_init(:md5),fn(line, acc) -> :crypto.hash_update(acc,line) end )
|> :crypto.hash_final
|> Base.encode16
{:ok, {~p"/uploads/#{Path.basename(dest)}", md5_hash}}
end)
end
def error_to_string(:too_large), do: "Too large"
def error_to_string(:not_accepted), do: "You have selected an unacceptable file type"
def error_to_string(:too_many_files), do: "You have selected too many files"
end
和我的领域模型
defmodule BotLeagueBackend.Wasm do
use BotLeagueBackend, :domain_model
alias BotLeagueBackend.User
@primary_key {:id, Ecto.UUID, default: Ecto.UUID.generate()}
schema "wasms" do
field :file_path, :string
field :md5_hash, :string
field :name, :string
field :active, :boolean, default: true
belongs_to :user, User, foreign_key: :user_id, type: :binary_id
timestamps()
end
def changeset(wasm, params \\ %{}) do
wasm
|> cast(params, [:file_path, :md5_hash, :name, :active, :user_id])
|> validate_required([:file_path, :md5_hash, :name, :active, :user_id])
|> validate_length(:file_path, max: 255, min: 1, message: "must be between 1 and 255 characters")
|> validate_length(:md5_hash, max: 32, min: 32, message: "invalid md5 hash")
|> validate_length(:name, max: 255, min: 1, message: "must be between 1 and 255 characters")
end
def new(
file_path: file_path,
md5_hash: md5_hash,
name: name,
active: active,
user_id: user_id
)
when is_binary(file_path) and is_binary(md5_hash) and is_binary(name) and is_binary(user_id) do
{:ok, user_id} = Ecto.UUID.cast(user_id)
wasm = %@self{
file_path: file_path,
md5_hash: md5_hash,
name: name,
active: active,
user_id: user_id
}
{:ok, wasm}
end
end
我的错误是什么?我的目标是,如果我输入超过 255 个字符的文本,则会显示错误消息。
我还没有完全检查您的代码,但根据我的经验,当变更集没有
:action
键集时,通常会发生这种情况。
您可以像
Map.put(changeset, :action, :validate)
一样简单地完成此操作。
当您使用变更集
Repo.insert
或 Repo.update
时,这些函数会自动将 :action
或 :insert
的 :update
放在变更集上。
我要尝试的第一件事就是改变这一点
@impl true
def handle_event("validate", %{"wasm_form" => params}, socket) do
wasm_form =
%Wasm{}
|> Wasm.changeset(params)
|> to_form(as: "wasm_form")
进入这个
@impl true
def handle_event("validate", %{"wasm_form" => params}, socket) do
wasm_form =
%Wasm{}
|> Wasm.changeset(params)
|> Map.put(:action, :validate)
|> to_form(as: "wasm_form")