Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rendering JSON in Phoenix

I used "mix phoenix.gen.json" to generate the code for rendering json resulting in view below:

defmodule Pghm.SightingsView do    
  use Pghm.Web, :view

  def render("sighting.json", %{sighting: sighting}) do
    %{what: sighting.what,
      lat:  sighting.lat,
      long: sighting.long}
  end

  def render("index.json", %{sightings: sightings}) do
    %{data: render_many(sightings, Pghm.SightingsView, "sighting.json")}
  end

  def render("show.json", %{sighting: sighting}) do
    %{data: render_one(sighting, Pghm.SightingsView, "sighting.json")}
  end
end

However when I attempt to access call it I receive: Could not render "sighting.json" for Pghm.SightingsView, please define a matching clause for render/2 or define a template at "web/templates/sightings". No templates were compiled for this module. Assigns:

Everywhere I've looked indicates that this should work, but I get no love.

like image 250
Donavan Stanley Avatar asked Jul 17 '16 23:07

Donavan Stanley


2 Answers

I started with Phoenix recently too, but probably I know what's the problem.

def render("sighting.json", %{sighting: sighting}) do
  %{what: sighting.what,
    lat:  sighting.lat,
    long: sighting.long}
end

The definition of this function says, that it will work only if you call it this way:

render("sighting.json", %{sighting: some_data})

But this code:

%{data: render_many(sightings, Pghm.SightingsView, "sighting.json")}

Passes a sightings itself to render's second parameter, not the required %{sighting: sighting} thing. So Elixir couldn't find a render implementation that suits given parameters and raises the error.

Changing

def render("sighting.json", %{sighting: sighting}) do

to just

def render("sighting.json", sighting) do

should do the trick.

like image 107
lech1 Avatar answered Nov 19 '22 02:11

lech1


I've had exactly this problem today, and it was because I pluralised the view's name, like in Rails.

According to comments in the Phoenix source (1), the key is inferred from the view name.

A collection is any enumerable of structs. This function returns the rendered collection in a list: render_many users, UserView, "show.html" is roughly equivalent to:

Enum.map(users, fn user ->
  render(UserView, "show.html", user: user)
end)

The underlying user is passed to the view and template as :user, which is inferred from the view name. The name of the key in assigns can be customized with the :as option

(1) https://github.com/phoenixframework/phoenix/blob/8a6beef9e13f049a8458db25b71fb70afae7673a/lib/phoenix/view.ex#L267

So try this :

defmodule Pghm.SightingView do    
  use Pghm.Web, :view

  def render("sighting.json", %{sighting: sighting}) do
    %{what: sighting.what,
      lat:  sighting.lat,
      long: sighting.long}
  end

  def render("index.json", %{sightings: sightings}) do
    %{data: render_many(sightings, Pghm.SightingView, "sighting.json")}
  end

  def render("show.json", %{sighting: sighting}) do
    %{data: render_one(sighting, Pghm.SightingView, "sighting.json")}
  end
end
like image 2
Julien De Coster Avatar answered Nov 19 '22 01:11

Julien De Coster