Columns Decimal + Repo

Has anyone ever experienced this?
When using Repo.all in a column (decimal)
Returns as follows.

products_list = Repo.all(from(c in Product, select: {[c.name, " - R$: ", c.value], c.id}))

Result:

[debug] QUERY OK source="products" db=0.5ms
SELECT p0."name", p0."value", p0."id" FROM "products" AS p0 []
[
  {["Host I", " - $: ", #Decimal<10.90>], 1},
  {["Host II", " - $: ", #Decimal<19.90>], 2},
  {["Host III", " - $: ", #Decimal<39.90>], 3},
  {["Host IV", " - $: ", #Decimal<59.90>], 4}
]

How do I remove this #Decimal, and only the number appears?

Decimal numbers are, by definition, fixed precision. And therefore they have to be represented in Elixir (and other languages) in some structured format to preserve the precision. In Elixir the decimal library is the go-to library as you have seen.

When iex calls a function, like Repo.all/1, it will Kernel.inspect/1 on the returned result so you can see it in a user-friendly fashion. This is not special to Repo functions in any way.

For Decimals that format is the common Elixir format for inspecting structs of #Decimal<10.90> as you have seen. This is a good thing. It tells you the structure and the value.

However its just the inspected format and not something you should be concerned about in any case I can think of.

Is there something in particular that makes this problematic for you?

2 Likes

I’ll explain my problem better …

In my form.html.eex I have this
<%= select(f, :product_id, @products_list, prompt: "Escolha seu produto", class: "form-control") %>

In my controller I have this

  def new(conn, _params) do
    changeset = Structure.change_request(%Request{})
    products_list = Repo.all(from(c in Product, select: {[c.name, " - R$: ", c.value], c.id}))

    render(conn, "new.html", changeset: changeset, products_list: products_list)
  end

When I preview open this form.html in my browser the following error arises.

[error] #PID<0.844.0> running ProjectWeb.Endpoint (connection #PID<0.745.0>, stream id 15) terminated
Server: localhost:4000 (http)
Request: GET /requests/new
** (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: #Decimal<10.90>
(phoenix_html) lib/phoenix_html/safe.ex:81: Phoenix.HTML.Safe.List.to_iodata/1
(phoenix_html) lib/phoenix_html/safe.ex:49: Phoenix.HTML.Safe.List.to_iodata/1
(phoenix_html) lib/phoenix_html/safe.ex:49: Phoenix.HTML.Safe.List.to_iodata/1
(phoenix_html) lib/phoenix_html.ex:147: Phoenix.HTML.html_escape/1
(phoenix_html) lib/phoenix_html/form.ex:1167: Phoenix.HTML.Form.option/4
(phoenix_html) lib/phoenix_html/form.ex:1138: anonymous fn/3 in Phoenix.HTML.Form.options_for_select/3
(elixir) lib/enum.ex:1940: Enum."-reduce/3-lists^foldl/2-0-"/3
(phoenix_html) lib/phoenix_html/form.ex:1112: Phoenix.HTML.Form.select/4
(project) lib/projectWeb/templates/request/form.html.eex:28: anonymous fn/2 in ProjectWeb.RequestView.“form.html”/1
(phoenix_html) lib/phoenix_html/form.ex:377: Phoenix.HTML.Form.form_for/4
(project) lib/project_web/templates/request/form.html.eex:1: ProjectWeb.RequestView.“form.html”/1
(project) lib/project_web/templates/request/new.html.eex:121: ProjectWeb.RequestView.“new.html”/1
(project) lib/projectWeb/templates/layout/app.html.eex:45: ProjectWeb.LayoutView.“app.html”/1
(phoenix) lib/phoenix/view.ex:410: Phoenix.View.render_to_iodata/3
(phoenix) lib/phoenix/controller.ex:729: Phoenix.Controller.put_render/5
(phoenix) lib/phoenix/controller.ex:746: Phoenix.Controller.instrument_render_and_send/4
(project) lib/project_web/controllers/request_controller.ex:1: ProjectWeb.RequestController.action/2
(project) lib/project_web/controllers/request_controller.ex:1: ProjectWeb.RequestController.phoenix_controller_pipeline/2
(phoenix) lib/phoenix/router.ex:288: Phoenix.Router.call/2
(project) lib/project_web/endpoint.ex:1: ProjectWeb.Endpoint.plug_builder_call/2

I believe the problem is related to the name #Decimal.
Would you have any suggestions to solve this?

This is mostly a mismatch between different parts of your application. Phoenix expects (for your case) a list of tuples, with a label and a value. Both need to be renderable by Phoenix.HTML, which is not the case for decimal structs. You’d need to convert the decimal to a string representation for phoenix to be able to render it in the way you showed.

It’s actually not related to the #Decimal<> construct. The message is an inspection of your content which as you know from the above has a certain output for decimals.

I believe you will need to convert your decimals to binaries first. I’m not familiar enough with Phoenix HTML rendering to help further. But I’m pretty confident thats the source of the issue.

As the others said, you aren’t formatting your Decimals in a way that is renderable in HTML. It does not happen automatically – Phoenix does not fantasise about how your data type can be shown in an inherently string format as HTML. So replacing the above with:

products_list = Repo.all(from(c in Product, select: {[c.name, " - R$: ", Decimal.to_string(c.value)], c.id}))

…should work. Also check out Decimal.to_string/2 for possible different formats.

This shouldn’t work because you cannot have elixir code in ecto queries. It would need to be done in a second step.

Well, we don’t want to do the entire work without challenging the OP a bit, do we? :wink:

But you are correct. Apologies. Just trying to put people on the right path.

Thank you all for your help.
I will try here with Decimal.to_string
But if anyone has any example, thank you too.