beechovsky
beechovsky

Reputation: 151

Phoenix Schema assigns throw Phoenix.HTML.Safe not implemented error in form select

I'm getting the following error:

protocol Phoenix.HTML.Safe not implemented for {"Bad Product, LLC"}

from the following code:

ReviewController

def new(conn, _params) do # creating a review, the Company is a schema association
    changeset = Accounts.change_review(%Review{})
    companies = Repo.all from c in Company, select: {c.name} 
    render(conn, "new.html", changeset: changeset, companies: companies)
end

Template:

<%= select f, :company_id, @companies %>

From researching on SO I've tried to add inspect:

<%= select f, :company_id, inspect @companies %>

but that throws the following error:

protocol Enumerable not implemented for "[{\"Bad Product, LLC\"}]"

It looks like it is trying to escape it as expected, so I refactored the controller to enumerate the companies:

render(conn, "new.html", changeset: changeset, companies: Accounts.list_companies() |> Enum.map(&{&1.name}))

but it still throws the Enumerable not implemented error.

Thanks!

Upvotes: 1

Views: 1289

Answers (3)

beechovsky
beechovsky

Reputation: 151

Thanks again to @sanjaykumar - they were partially correct and helped lead me in the right direction.

Including the id helped, but loading the entire schema was unnecessary. All of the following solutions work:

render(conn, "new.html", changeset: changeset, companies: Accounts.list_companies() |> Enum.map(&{&1.name, &1.id}))

or

render(conn, "new.html", changeset: changeset, companies: Repo.all(Company) |> Enum.map(&{&1.name, &1.id})) 

or, what I'm going with:

companies = Repo.all from c in Company, select: {c.name, c.id}

I have limited experience with Elixir and Phoenix, but I suspect that this 3rd query is better than the other two, which are effectively the same other than Accounts.list_companies() resulting in another function hitting the call stack. They bring the entire Company into memory (I'm guessing), while I suspect the 3rd query only grabs the fields specified. They both also call Enum.map, so another function call.

Upvotes: 1

Sanjay Kumar
Sanjay Kumar

Reputation: 41

yes

When we call Repo.all(Company), it will load all columns of table, it also loads metadata.If we have huge amount of data there will be performance issue.

The 3rd query you have used, will return list of columns you required.This will definitely going to save bandwidth.

Upvotes: 1

Sanjay Kumar
Sanjay Kumar

Reputation: 41

companies = Repo.all from c in Company, select: {c.name}

Here you are only selecting name

And you are trying to access company_id

Try

companies = Repo.all(Company)

Upvotes: 2

Related Questions