UndefinedFunctionError when trying to add html views to json api server

Hi All, I am setting up some html routes on a json api server that I’ve
been working and am missing an important step. The error message is
listed first, then the code that I have added that seems relevant.

Error message

UndefinedFunctionError at GET /print/documents/1
function Koko.Web.LayoutView.render/2 is undefined (module Koko.Web.LayoutView is not available)

router.ex

  pipeline :browser do
   plug :accepts, ["html"]
   plug :fetch_session
   plug :fetch_flash
   plug :protect_from_forgery
   plug :put_secure_browser_headers
 end

  scope "/print", Koko.Web do
    pipe_through :browser
    get "/documents/:id", PrintController, :show
  end

print_controller.ex

defmodule Koko.Web.PrintController do
  use Koko.Web, :controller
  alias Koko.Repo
  alias Koko.DocManager.Document

  def show(conn, %{"id" => id}) do
    document = Repo.get(Document, id)
    render conn, "plain.html", document: document
  end

end

templates/print/plain.html

<div id="rendered_text" class="rendered_text">
   <%= raw(@document.rendered_text) %>
</div>

There is also a koko_web.ex with a lot of boilerplate.

That means it will do an html render, which since you are using the Phoenix helper it will auto-specify a layout option (which you can set to nil to disable). Since I’m guessing you don’t need the whole layout stuff you can just call Koko.Web.PrintView.render("plain.html", document: document) directly and skip it.

Or you can make a LayoutView and add a (filled or empty) layout. :slight_smile:

1 Like

I think I am close, but still not there. The code

def show(conn, %{"id" => id}) do
    document = Repo.get(Document, id)
    Koko.Web.PrintView.render("plain.html", document: document)
  end

gets much futher than before but gives the error

expected action/2 to return a Plug.Conn, all plugs must receive a connection (conn) and return a connection

Hmm …

Render on a View returns an IOList, so you need to put that into the ‘body’ on the conn then return that conn.

Sorry, I guess I am in a little over my head here. I tried this:

def show(conn, %{"id" => id}) do
    document = Repo.get(Document, id)
    response = Koko.Web.PrintView.render("plain.html", document: document)
    assign(conn, :resp_body, response)
end

But this is not the way to do it. Are there places I can read up on this?

def show(conn, %{"id" => id}) do
  document = Repo.get(Document, id)

  conn
  |> put_layout(false)
  |> render("plain.html", document: document)
end

Alternatively, add

plug :put_layout, false

to the top of your controller.

1 Like

Thanks, that does it!

Thanks!!

Yay! More elegant.