Amber: Unable to render layout in directory

Created on 23 Oct 2017  路  12Comments  路  Source: amberframework/amber

Description

Defining a layout in a sub-directory of src/views/layouts causes compilation error:

expanding macro
in macro 'embed' /Users/adampaterson/Code/garnet-app/lib/kilt/src/kilt.cr:12, line 4:

   1.
   2.
   3.
>  4.       Slang.embed("layouts/new_app/new_application.slang", "__kilt_io__", )
   5.
   6.

expanding macro
in macro 'embed' /Users/adampaterson/Code/garnet-app/lib/slang/src/slang/macros.cr:2, line 1:

>  1.     {{ run("slang/slang/process", "layouts/new_app/new_application.slang", "__kilt_io__") }}
   2.

Error executing run: slang/slang/process "layouts/new_app/new_application.slang" "__kilt_io__"

Got:

Steps to Reproduce

  1. Create controller
    src/controllers/new_controller.cr
class NewController < ApplicationController
  LAYOUT = "new_app/new_application.slang"

  def index
    render("new_app/index.slang")
  end
end
  1. Add route
    config/routes.yml
routes :web do
  get "/new", NewController, :index
end
  1. Create layout
    src/views/layouts/new_app/new_application.slang
body
  == content
  1. Create view
    src/views/new_app/index.slang
h1 New Application
  1. Build (or amber watch)

Expected behavior:

  • Layout is rendered with content from view

Actual behavior:

  • Compilation error

Reproduces how often:

  • 100%

Versions

  • Crystal 0.23.1 (2017-10-12) LLVM 4.0.1
  • Amber CMD (amberframework.org) - v0.3.0
  • macOS High Sierra 10.13.1 Beta (17B35a)

Additional Information

  • I've tried to debug this but only have lldb setup and have no access to vars in my IDE.

  • Replacing render() with what the macro should be generating works as expected

content = Kilt.render("src/views/new_app/index.slang")
Kilt.render("src/views/layouts/new_app/new_application.slang")
  • I've tried a combination of render including defining all params in my call
  • src/view/layouts/new_application.slang works when in the parent layouts directory
not-a-bug

Most helpful comment

Great work on #328 @elorest, thank you. Although looking back, you're correct about the path I should be taking for my admin layout, this will certainly help when I'm creating other layouts in similar way. admin/login.slang for example.

All 12 comments

I can reproduce this issue

Amber render wrapper is here

I've tried to debug this but only have lldb setup and have no access to vars in my IDE.

Try using gdb also see: Debugging Crystal using GDB

Why do you want your view to be in a folder named differently from the controller?

  def index
    render("new_app/index.slang")
  end

render is a magic method that finds the directories for you based upon convention and what controller your in.

If you controller is called NewController then your views should be a src/views/new/ and your layouts should be in src/views/layouts/

LAYOUT = "new.slang"
# and
render("index.slang")

If you choose to ignore conventions you have 2 options:

  1. Use full paths
LAYOUT = "src/views/layouts/new_app/new_application.slang"
# and
render("src/views/new/new_app/index.slang") 
  1. Just use kilt.
content = Kilt.render("src/views/new_app/index.slang")
Kilt.render("src/views/layouts/new_app/new_application.slang")

@elorest but this issue also happens when you try to change the layout location

class ApplicationController < Amber::Controller::Base
  LAYOUT = "foo/application.slang"
end

@faustinoaq true. I addressed that above though. If you want to change the assumed layout location, you need to use the full path. LAYOUT = "src/views/layouts/new_app/new_application.slang"

Rails also requires you to use the full path if you go outside of the expected folders. Although it does assume app/views for you when you hardcode it.

@adam-paterson Does that help?

@elorest this is the actual layout and view
src/controllers/admin/base_controller.cr
src/views/layouts/admin/application.slang
src/views/views/admin/index.slang

I don't believe this breaks convention. If it does I still think a user should be separate their layouts. I simply want to have all admin controllers in a different directory to the frontend directories. Same issue would apply if I wanted to keep my layouts directory clean by separating different application areas.

For Example:
layouts/cms/
layouts/blog/
layouts/catalog/
layouts/rss

All would fail without implicitly defining them using a full path.

@elorest I think the information is a good candidate to be in the guides.

@adam-paterson Other than the layouts everything in that list is within convention. However your steps to reproduce above were all out of convention.

Why are you creating layouts/admin/application.slang instead of layouts/admin.slang This would fail in rails as well without a full path.

@eliasjpr Good point. I'll do it.

@adam-paterson Most likely you'll like this. https://github.com/amberframework/amber/pull/328

Great work on #328 @elorest, thank you. Although looking back, you're correct about the path I should be taking for my admin layout, this will certainly help when I'm creating other layouts in similar way. admin/login.slang for example.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

olegsobchuk picture olegsobchuk  路  5Comments

faustinoaq picture faustinoaq  路  5Comments

nicbet picture nicbet  路  7Comments

sumwatt picture sumwatt  路  4Comments

faustinoaq picture faustinoaq  路  4Comments