Adding GitHub flavoured Markdown with syntax highlighting in your Rails application

Victor Martinez
Señor Developer
July 14, 2024

When faced with the task of selecting Markdown processors and syntax highlighting libraries, a plethora of options unfolds before us, each with its own merits. If, like us, you are a daily user of GitHub, there's an advantage in embracing the familiarity and convenience offered by GitHub Flavored Markdown.

If you are writing a blog or something else to render content in a Rails app, using this syntax is a sensible choice. Adding support for that to Rails apps is simple. Below we will demonstrate using two gems: Redcarpet to render Markdown syntax to HTML and Rouge to add syntax highlighting of code.

Rendering Markdown

To render Markdown we will use the redcarpet gem. There are a number of gems to do this, however Redcarpet excels in seamless integration with Ruby on Rails applications, offering a straightforward approach that follows the Rails way of doing things. An alternative is Kramdown, which has an emphasis on speed and efficiency, so for high traffic websites that may be a better option.

Let's start by creating a MarkdownService that will take a Markdown string and return rendered HTML:

require 'rouge/plugins/redcarpet'

class MarkdownService
  class Renderer < Redcarpet::Render::HTML
    include Rouge::Plugins::Redcarpet
  end

  attr_reader :markdown

  def self.call(markdown)
    new(markdown).call
  end

  def initialize(markdown)
    @markdown = markdown
  end

  def call
    render
  end

  private

  def markdown_renderer
    Redcarpet::Markdown.new(
      Renderer,
      autolink: true,
      tables: true,
      fenced_code_blocks: true
    )
  end

  def render
    markdown_renderer.render(markdown)
  end
end

The necessary option that will allow us to render and enable syntax highlighting similar to GitHub is fenced_code_blocks.

Example of fenced code block:

```ruby puts 'Hello WatchSumo!' ```

Calling MarkdownService.call([...]) will render it as Markdown and additionally process all the fenced code blocks, returning HTML that can be styled with pygments compatible stylesheets.

Styling

There is a nice collection available under pygments-css repository.

By default, the main highlight class will be called highlight in Rouge. To make this work with pygments you will need to alter the CSS. Change .hll to .highlight, like this:

.hll { background-color: #ffffcc }

to

.highlight { background-color: #ffffcc }

An alternative is to override the redcarpet plugin, by passing the correct class name for compatibility:

class Renderer < Redcarpet::Render::HTML
  include Rouge::Plugins::Redcarpet

  protected

  def rouge_formatter(opts = {})
    ::Rouge::Formatters::HTML.new(opts.merge({ css_class: "hll" }))
  end
end

An additional option that you might be interested in adding is line_numbers: true that enables line numbers in the output.

Conclusion

In conclusion, choosing Markdown processors and syntax highlighting libraries for a Rails application is a nuanced decision, with GitHub Flavored Markdown offering familiarity and convenience. This article demonstrated a straightforward implementation using Redcarpet for Markdown rendering and Rouge for syntax highlighting.