Closed sdogruyol closed 2 years ago
ECR generates Crystal code like this for the content template:
content_io << "main"
content_for "title" do
content_io << "block"
end
The content_for
macro expands to creating a Proc with the body of the macro block.
When that block is called from yield_content
, it returns the value of the last expression (content_io << "block"
) which is the IO content_io
. At this point, it already contains all the previously appended content ("main" in this example) and thus it is part of the return value.
In order to achieve the intended behaviour here, the proc call needs to be wrapped by setting content_io
to a fresh instance.
Something like this should work:
if __content_filename__ == __caller_filename__
%old_content_io, content_io = content_io, IO::Memory.new
%proc.call
%result = content_io.to_s
content_io = %old_content_io
%result
end
You rock @straight-shoota 🤘 That worked like a charm 👍
Related to https://github.com/kemalcr/kemal/issues/636, I discovered that
content_for
is not capturing and yielding the correct block input inside theecr
view. It weirdly captures the whole content of the fileTake this for example:
src/views/home.ecr
src/views/layout.ecr
src/kemal-bug.cr
When you go to
/
you'd expect the correct output with<meta>
tag inside the<head>
tag however this is the following output.the
Hello world
outside of the block insrc/views/home.ecr
is also captured by thecontent_for
block and then yielded again which leads to duplicate content. For more info here's where it's yielded in thecontent_for
macro https://github.com/kemalcr/kemal/blob/master/src/kemal/helpers/macros.cr#L37I think the wrong capture of the block might be a bug in Crystal itself in ECR, WDYT @straight-shoota?