Sometimes, it’s the little things that matter the most. As cool and complex as your giant application might be, small details like a toggleable button, or beautiful-formatted and styled dropdown select can have the biggest impact on the look and feel of the rest of your application.
Once you’ve built out the skeleton of your application and filled in the backend functionality, the next step is to connect the all the logic with your frontend framework. And once you’ve done that, you start to see all the gaping holes that you need to fix next. One of the applications that I have been working on recently got to that state. Once I ensured that the user-facing page corresponded to the admin panel, it was time to fix all the little things that I had been putting off until we got the application working!
One of those minute details was rendering markdown. While building out the application, we were just using Ruby string primitives in our database to render text. But no one wants to see a long five-paragraph article rendered as a single, huge block of text, right? So, we had to make our text easily editable on the admin panel and renderable — that’s word, right? — on the user-facing side. At first, I had no idea how to go about doing this. But it turns out that (no surprise here!) this problem has been solved before! All we had to do next was figure out how to implement someone else’s solution on our own application. Luckily, the answer to our prayers is as simple as rolling out the redcarpet
gem.
Markdown: What is it?
The Markdown language didn’t exist until 2004, when it was created by John Gruber of Daring Fireball blog fame. Unlike markup languages such as HTML or RTF (Rich Text Format), Markdown was created to not have any tags for formatting “instructions” when rendered. Instead, it is structured to be readable without formatting or any tags. Ultimately, the language converts simple text into structurally valid markup HTML (or XHTML).
We interact with Markdown a lot, even though we might not always realize it. Files that end in .md
, for example, are written in Markdown, and a lot of blog generators (including octopress and jekyll) use Markdown as their formatting language. In fact, this language is exactly what allows us to write something like this into a code snippet or CMS parser:
1 2 3 4 5 6 7 8 9 |
|
which will then be processed by Markdown to render actually this HTML in our templates:
1 2 3 4 5 6 7 8 9 10 11 |
|
Not only is that incredibly cool, but it’s also a powerful templating tool! There’s one slight problem, however: our templates don’t look anything like this. We have neither any Markdown, nor any HTML! Instead, we’re just rendering long strings (saved in our Postgres database as text
attributes) that look like this:
Here's a news article about Harper Lee's new novel, Go Set A Watchman, but it has no formatting at all...
So, how do we get our text to look like the beautiful markup from above? Why, by using a special Markdown gem, of course!
HTML All Of The Things
Markdown processig in Ruby is made especially easy thanks to a library called redcarpet
, created by a Github developer named Vicent Marti (thanks, Vicent!). The library is available as a gem, and its parser doesn’t require any additional installed libraries aside from Ruby itself.
Let’s get set up by adding it to our Gemfile
:
gem "redcarpet"
and bundling up this gem:
$ bundle install
Great. Now we need figure out how to recarpet our application using this library! The first thing I like to do whenever I’m working with a library or gem that’s completely new to me is decipher what exactly I’m working with here. Thankfully, the redcarpet
documentation is really fantastic, and they answer this question almost immediately:
“The core of the Redcarpet library is the Redcarpet::Markdown class. Each instance of the class is attached to a Renderer object; the Markdown class performs parsing of a document and uses the attached renderer to generate output.”
Okay…what does this mean, exactly? Well, it’s actually not too complicated. The library has a Redcarpet::Markdown
class, which — you guessed it — is going to be responsible for handling the transforming/parsing of Markdown to markup (we’ll be using HTML, in our case). But it’s also attached to a Renderer object, it seems.
An example will help us visualize what exactly is going on here:
markdown = Redcarpet::Markdown.new(renderer, extensions = {})
Interesting! the new instance of our Redcarpet::Markdown
class takes two arguments, one of which is our Renderer object. It also seems to take a hash of extensions
, but we’ll come back to that in a bit.
We know that we want to pass in a renderer to our Redcarpet::Markdown
class…but what are our options? It turns out that there are two built-in renderers that the redcarpet
library uses: Redcarpet::Render::HTML
and Redcarpet::Render::XHTML
.
Protip: the redcarpet
renderers are actually implemented in C, which means that they are incredibly performant and so much faster than other Ruby Markdown renderers!
Since we want our articles to render HTML, we’ll stick with the former renderer rather than the latter:
markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML)
It’s important to note that what’s actually happening here is that we are creating a new instance of an HTML renderer, and passing that to our Redcarpet::Markdown
object. This is crucial to remember because our Redcarpet::Render::HTML
can also take its own set of options! When we initialize our HTML renderer, we have the option of passing some flags to it. And then, we pass our HTML renderer to our markdown
object, which will actually handle parsing it:
1 2 |
|
We won’t add any options to start, but don’t forget that this is what’s actually happening! Now it’s time for a deep breath; next, we’ll need to actually implement this markdown
object in our application!
The first thing we’ll want to do is add our markdown
object to the class that will need our Markdown parser. For our Bookstore application, we’ll have a set of news articles that will show up on our homepage when a user signs in. This means that we’ll want our Article
objects to be able to implement markdown. Since this is something our entire class should be able to do, we’ll add our markdown
object as a class method to our Article
model:
1 2 3 4 5 6 7 |
|
This method isn’t doing anything aside from creating a new instance of a Redcarpet::Markdown
parser, with a Redcarpet::Render::HTML
renderer. Next, we’ll want to add write a migration that will create another column in our database that will save our markdown content:
1 2 3 4 5 |
|
The reason that we have two different columns for persisting content is simple: we have two different types of content that we’re dealing with. The content
column in the database is what the admins will edit in the admin panel, while the markdown_content
column is what will be rendered to the user.
This will be especially evident when we integrate this with our Ember frontend, which would require us to serialize all the data that Rails is passing to the Ember models. In our ArticleSerializer
, we are are only passing our markdown_content
through to the frontend:
1 2 3 |
|
On the other hand, in our Admin::ArticleSerializer
, which is hooked up to our admin panel, we are only passing the raw :content
, which is our content before is has been parsed through our markdown
object:
1 2 3 4 5 |
|
Nice! We have everything set up, finally. Let’s make sure that we’re actually parsing our content
and assigning our markdown_content
when our article is saved. We can do this by adding a before_save
hook, which will call whatever method we pass it right before our Article
model is saved:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
Cool! We wrote a assign_markdown_content
method that assigns the markdown_content
attribute on our Article
. And what exactly is it using to assign the markdown_content
? Oh, that’s right: our markdown
object! We’re calling the markdown
class method, and passing the Article
’s content to its render
method, which means that the Redcarpet::Markdown
instance will parse the content into HTML!
We’re also doing a pre-check in our before_save
by passing a proc to this callback which will only call the assign_markdown_content
method if our content
column in the database has changed (isn’t that content_changed?
method is a cool ActiveRecord trick?). This means that we’re not assigning attributes on our Article
unless we really need to. This is super efficient because it means avoiding unnecessary queries to our database!
Carpeting Options
The last part of this redcarpet
magic is rendering our content in our views and adding any options we might need. If we wanted to do this in a simple Rails view, we could just ask the Article
object for its markdown_content
:
1 2 |
|
We might need to call html_safe
on this particular column since Rails will try to escape the content automatically. We could do a similar thing in an Ember view as well, using triple handlebars to handle the HTML safe issue.
Now that we finally have everything working, we can add some cool options to our renderer! You’ll remember that the Redcarpet::Markdown
class takes a hash of options.
In my opinion, the most helpful and important option to pass in is autolink
. It’s super crucial if you don’t know what your content might look like, since it parses links even when they’re not enclosed in < >
characters. It will detect autolinks for http, https, and ftp protocols, and it also handles email addresses and links that start with www
.
We can pass in this option directly as second arguments after we pass in our Redcarpet::Render::HTML
object:
1 2 3 |
|
Other helpful options on the Redcarpet::Render::HTML
object include tables
, space_after_headers
, lax_spacing
, and highlight
. Of course, just as you can pass in options to the markdown object you can do the same for the renderer:
Redcarpet::Render::HTML.new(hard_wrap: true, safe_links_only: true, escape_html: true)
The escape_html
option is particularly interesting because it takes precedence over :no_styles
, :no_links
, :no_images
and :filter_html
, which means that any existing html tags will be escaped instead of being removed. I’m also pretty sure that it would escape any cats you try to pass in through params as well…although I haven’t tried that one yet.
tl;dr?
- The
redcarpet
gem is an awesome way to handle rendering Markdown in Rails. It creates a new instance of a Markdown object, which takes either a HTML or XHTML renderer object. You can also write your own, custom render! Check out the documentation to learn more on how to do that. - Want to see a step-by-step Rails tutorial on
redcarpet
? Check out this Railscast. - Here’s a super detailed blog post on implementing
redcarpet
, with some great code snippets and examples.