kccarter
We’re trying to create a form using the .form component and a map but unable to figure out the right combination. We are not using Ecto. Our data is unstructured JSON stored in a NoSQL backend.
The documentation says to use to_form with a map, but we keep getting stuck with the error that the given map does not implement HTML.Safe.
<.form :let={f} for={@account} action={~p"/accounts/#{@tag["id"]}"}>
# We know there's always a name, but in reality
# this is a for-loop over the account's keys.
<.input field={f["name"]} />
</.form>
defmodule DemoWeb.AccountsController do
def edit(conn, %{"id" => id}) do
# This returns a Map of arbitrary key/value pairs.
account = Accounts.find!(id)
# Is this what we're supposed to do?
account_form = Phoenix.Component.to_form(account)
render(conn, :edit, account: account_form)
end
end
Our goal is to just render a form for a map, and then have the form fields posted back to the appropriate endpoint, where we’ll convert it back to a JSON blob and store it accordingly. Ecto, and Ecto changesets, are not used anywhere.
Trending in Questions
I having some trouble figuring out if I have set myself too strict of standards for my production server. Currently I can handle 75% of r...
New
Hello,
I’m trying to build a basic Phoenix web-app, and I’d like to use Tailwind.
However, when I launch mix phx.server, I get an error...
New
I’m working on a small exercise involving update_in/3, and I came up with this solution:
data = %{
name: "Periodic Table",
category:...
New
I’ve got trouble wrapping my head around the order in which functions are called in this snippet (from Phoenix’s authentication):
toke...
New
Hello folks!
So at work, we are seeing some situations where we have to define some “fixed” strings that are used across the codebase in...
New
Is there any way to avoid the Hologram compiler running when using iex? It seems like the front-end code could potentially be disregarded...
New
** (ArgumentError) expected :max_attempts to be a positive integer, got: {:@, [line: 10, column: 19], [{:max_attempts, [line: 10, column:...
New
Other Trending Topics
Edit: 2026 May 15 - This post is archived.
Mob is alive!!
Main docs: mob v0.7.11 — Documentation
A bit of explanation for the slightly c...
New
I am happy to introduce the very α version of the new programming language compiled to BEAM.
Welcome Cure.
It has literally three kille...
New
Hobbes is a low-level distributed database for the Elixir programming language.
Hobbes provides a simple, safe, and scalable storage lay...
New
A little off-topic, but I feel like people here have a good head on their shoulders.
I used to be quite good at making software. Was luc...
New
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ai
- #ecto-query
- #elixirconf-us
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #elixirconf-eu
- #api
- #forms
- #security
- #metaprogramming










Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
sodapopcan
Where is
tagcoming from? Ifaccountis a map, then this is the general idea:then in the template:
kccarter
My bad.
tagwas meant to beaccount.sodapopcan
I’m assuming
accountis a struct since that would cause that error. You have to use either a bare map or a changeset withto_form. You can convert a struct to a map withMap.from_structalthough you’ll get a warning that you should not be using atom keys withto_form. From there you could convert all the keys to strings but I would just use a changeset. Since you aren’t using changesets anywhere else, you won’t need to do anything else with them other than convert your struct to one just for use with the form:changejust creates a changeset, no-questions-asked (no casting or anything) so it literally only needs to exist for the form.kccarter
Accountwas just a Map. The following still produces an error:Produces this error:
That code above seems to be converting a normal Map using
to_formas suggested by the documentation, but we’re obviously missing an important step.sodapopcan
Ohhhh crap, I’m sorry. It’s been a million years since I’ve used a controller with a form like that. AFAIR, you just use the bare map, no need for
to_form.to_formis largely about change tracking which is a LiveView-specific thing. You can just do:The
asoption will let you collect the params under an"account"key.kccarter
Awesome. Thank you.
We also noticed another issue that was causing a Safe HTML error but wasn’t related to the form, but rather a line further down in the heex file. Fridays..
sodapopcan
That basically means you are trying to
to_stringsome value into HTML. Most of the time it’s a struct, but it could be a tuple or fun or whatever doesn’t cast into a string (or HTML in this case, to be a bit more technical).Sebb
EDIT this anwser is OT, because this is about Controllers, not LV.
IF YOU’D BE USING LIVEVIEW you should not use
:lethere, see: Phoenix.Component — Phoenix LiveView v0.20.7This works WITH LV:
sodapopcan
You’re making a similar mistake that I made—they are using controllers, not LiveViews.
to_formjust doesn’t work with controllers (from the bit of testing I did). And because of this it doesn’t really matter if they use:letor not (I also had the same thought, though).kccarter
Yeah, in a framework with relatively good documentation, we’ve found the narrative around forms to be a bit confusing and hard to follow. We’re not using LiveView, so the fact that
.formis part ofPhoneix.LiveViewinitially made us look past it.There’s
form_forinPhoenix.HTMLbut this blog post suggests that it’s now deprecated. And this older forum post has a post from Jose saying that.formis the correct way to go, but as noted above we initially thought that was just for LiveViews.In
core_components.exthere’s.simple_formwhich is used throughout the generated scaffolding code. In this case you can quickly see it just calls through to.form, but when you’re initially learning it’s an added layer of indirection.In our case, where we’re just using a plain
Map, the “secret” attribute to make it work wasas:.We’re editing JSON records with an arbitrary and unknown set of keys. All we really want a
formcomponent for is to have the proper_methodand_csrfattributes injected along with proper field naming.