Markdown and Code Blocks with Redcarpet and Rouge

Created: December 07, 2018 10:05 | Updated: December 15, 2018 12:07
Tags: Rails 5, Sass

My first thought when I was creating this website was:

“How do I make my code blocks look nice if I don’t have a built-in content management system?”

Jekyll handles this nicely with Kramdown, but for Rails the solution needs 2 gems and a little bit of code.

Initial code

First add the redcarpet and rouge gems to your gemfile

# Gemfile

gem 'redcarpet'
gem 'rouge'

Then install your gems

# bash
bundle install

You can then add your code to your application helper. This is just pulling in the Redcarpet gem for markdown, adding rouge for code blocks, and setting the extensions.

# application_helper.rb

module ApplicationHelper
 require 'redcarpet'
 require 'rouge'
 require 'rouge/plugins/redcarpet'

 class MarkdownRender < Redcarpet::Render::HTML
   def initialize(extensions = {})
     super extensions.merge(link_attributes: { target: '_blank' })
   end
   include Rouge::Plugins::Redcarpet
 end
end

Sass

The code blocks use CSS for highlighting, so add the following to your sass file to make things pretty

// application.scss

.highlight {

 border-radius: 5px;
 font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen-Sans, Ubuntu, Cantarell, Helvetica Neue, sans-serif;
 font-weight: normal;
 font-size: 15px;
 padding: 10px;
 padding-bottom: 0px;
 margin-bottom: 20px;

 pre {
   padding-bottom: 10px;
 }

 code,
 pre {
   color: #fdce93;
   background-color: #3f3f3f;
 }

 .hll {
   background-color: #222;
 }

 .err {
   color: #e37170;
   background-color: #3d3535;
 }

 .k {
   color: #f0dfaf;
 }

 .p {
   color: #41706f;
 }

 .cs {
   color: #cd0000;
   font-weight: 700;
 }

 .gd {
   color: #cd0000;
 }

 .ge {
   color: #ccc;
   font-style: italic;
 }

 .gr {
   color: red;
 }

 .go {
   color: gray;
 }

 .gs {
   color: #ccc;
   font-weight: 700;
 }

 .gu {
   color: purple;
   font-weight: 700;
 }

 .gt {
   color: #0040D0;
 }

 .kc {
   color: #dca3a3;
 }

 .kd {
   color: #ffff86;
 }

 .kn {
   color: #dfaf8f;
   font-weight: 700;
 }

 .kp {
   color: #cdcf99;
 }

 .kr {
   color: #cdcd00;
 }

 .ni {
   color: #c28182;
 }

 .ne {
   color: #c3bf9f;
   font-weight: 700;
 }

 .nn {
   color: #8fbede;
 }

 .vi {
   color: #ffffc7;
 }

 .c,
 .preview-zenburn .highlight .g,
 .preview-zenburn .highlight .cm,
 .preview-zenburn .highlight .cp,
 .preview-zenburn .highlight .c1 {
   color: #7f9f7f;
 }

 .l,
 .preview-zenburn .highlight .x,
 .preview-zenburn .highlight .no,
 .preview-zenburn .highlight .nd,
 .preview-zenburn .highlight .nl,
 .preview-zenburn .highlight .nx,
 .preview-zenburn .highlight .py,
 .preview-zenburn .highlight .w {
   color: #ccc;
 }

 .n,
 .preview-zenburn .highlight .nv,
 .preview-zenburn .highlight .vg {
   color: #dcdccc;
 }

 .o,
 .preview-zenburn .highlight .ow {
   color: #f0efd0;
 }

 .gh,
 .preview-zenburn .highlight .gp {
   color: #dcdccc;
   font-weight: 700;
 }

 .gi,
 .preview-zenburn .highlight .kt {
   color: #00cd00;
 }

 .ld,
 .preview-zenburn .highlight .s,
 .preview-zenburn .highlight .sb,
 .preview-zenburn .highlight .sc,
 .preview-zenburn .highlight .sd,
 .preview-zenburn .highlight .s2,
 .preview-zenburn .highlight .se,
 .preview-zenburn .highlight .sh,
 .preview-zenburn .highlight .si,
 .preview-zenburn .highlight .sx,
 .preview-zenburn .highlight .sr,
 .preview-zenburn .highlight .s1,
 .preview-zenburn .highlight .ss {
   color: #cc9393;
 }

 .m,
 .preview-zenburn .highlight .mf,
 .preview-zenburn .highlight .mh,
 .preview-zenburn .highlight .mi,
 .preview-zenburn .highlight .mo,
 .preview-zenburn .highlight .il {
   color: #8cd0d3;
 }

 .na,
 .preview-zenburn .highlight .nt {
   color: #9ac39f;
 }

 .nb,
 .preview-zenburn .highlight .nc,
 .preview-zenburn .highlight .nf,
 .preview-zenburn .highlight .bp,
 .preview-zenburn .highlight .vc {
   color: #efef8f;
 }
}

Markdown text

I use “Posts” for modelling my blog posts in Rails.

rails generate scaffold Posts

Therefore I will use my posts helper for the markdown_text function, which references code in the application helper. This function takes a string full of markdown and spits out HTML.

# posts_helper.rb

include ApplicationHelper

module PostsHelper
 def markdown_text(text)
   Redcarpet::Markdown.new(MarkdownRender, fenced_code_blocks: true).render(text).html_safe
 end
end

I can now call that function in any erb file referenced by the posts_controller

# _post.html.erb

<%= markdown_text(@post.content) %>

or

# some_file.html.erb

<%= markdown_text(“##Anything I want!”) %>

Markdown files

Now something else I wanted to do was create static markdown pages (not just dynamic blog posts).

I generated a controller (with one page in this example)

rails generate controller Static index

And I created a markdown file in /app/assets/markdowns/

example.md

# Title

Wow look at this page!

[Here is a link to Google!](https://www.google.com)

I add my markdown_file function to the static helper. Note how I reference the /app/assets/markdowns/

# static_helper.rb

include ApplicationHelper

module StaticHelper
 def markdown_file(filename)
   path = Rails.root.join('app', 'assets', 'markdowns', filename)
   text = File.read(path)
   Redcarpet::Markdown.new(MarkdownRender, fenced_code_blocks: true).render(text).html_safe
 end
end

And then I can reference the file in my index

# index.html.erb

<%=  markdown_file('example.md') %>

And it is done!

Written by Alan Vardy. Let me know how I can make this better!