ruby-on-railsimagemarkdownredcarpet

Rails is inserting element in the wrong position on HTML-Output. Wrong Syntax?


this is probably quite simple, but I tried solving it now for a longer time.

I have a helper method picture(file, alt) and a customized image-tag for the Markdown converter RedCarpet.

The helper method creates a <picture>-tag with a given file and alt-text. The custom Redcarpet renderer uses this picture(file, alt) method to compose a div.image including the picture-tag and an additional caption. The div.caption should go after the <picture>-tag inside of the div.image. But for some reason, my RedCarpet renderer includes the div.caption into the <picture>-tag.

like:

<div class="project-body-image">
  <picture>
    ...
    <div class="caption"></div>
  </picture>
</div>

Visually it works aswwell, but according to the W3C validator it should go outside.

How to get the div.caption oustide of the picture-tag? Additionally, is this a good way of outputting HTML from a method?

application_helper.rb:

def picture(file, alt)
    @html =   "<picture>" + 
                "<!--[if IE 9]><video style='display: none;''><![endif]-->" + 
                "<source media='(min-width: 0px)' sizes='1280px' srcset='" + file.url + " 1280w'>" + 
                "<!--[if IE 9]></video><![endif]-->" + 
                "<img src='" + file.url + "' alt='" + alt + "'>"
              "</picture>"
    @html.html_safe
end

custom_redcarpet.rb:

require 'redcarpet'

class CustomRedcarpet < Redcarpet::Render::HTML
  include ApplicationHelper

  # Custom Image tag like ![id](filename)
  def image(link, title, alt_text)
    # Use alt_text for record id
    # if you don't find anything return nothing: ""
    if Part.exists?(link)
      @part = Part.find(link)
      @file = @part.file
      @caption = @part.description

      @html = "<div class='project-body-image'>" + 
              picture(@file, @caption) + 
              "<div class='caption'>" + @caption + "</div>" + 
              "</div>"
      @html.html_safe
    else
      nil
    end

  end
end

Solution

  • You are missing + at the end of this line:

    "<img src='" + file.url + "' alt='" + alt + "'>"
    

    This thereby renders an unclosed <picture> tag. But since I think browsers automatically auto-closes incomplete tags, then that is why you still see <picture></picture> properly closed in your snippet.

    "Additionally, is this a good way of outputting HTML from a method?"

    Usually, I use content_tag when building up a render-able view inside a helper action. But since your rendered view has <!--[if IE 9]>, I would do it like you do (using concatenated string). The only difference I might do is to use multiple-lined string using <<-EOS like the following:

          @html = <<-EOS
    <picture>
      <!--[if IE 9]><video style='display: none;''><![endif]-->
      <source media='(min-width: 0px)' sizes='1280px' srcset='#{file.url} 1280w'>
      <!--[if IE 9]></video><![endif]-->
      <img src='#{file.url}' alt='#{alt}'>"
    "</picture>"
          @html.html_safe