RailsでMarkdownを読み書きする方法

目次

概要

RailsでMakdown形式の文章を保存して、それを元にHTMLを生成したいということがありました。

そこで、私はredcarpetというGemを使ってMarkdownの読み書きを実現したので、どのようにしてMarkdownを読み書きできるようにしたのかをここに書いておきます。

さらに今回、コードの記述などに色を付けるシンタックスハイライトについても設定をしたので、その設定も含めてここに書きます。

Gemのインストール

Markdownの読み書きには、redcarpetというGemを使います。

シンタックスハイライトには、rougeというGemを使います。

Gemfileに次の2行を追記します。

gem 'redcarpet'
gem 'rouge'

追記したら、bundle installでGemのインストールをします。

使い方

redcarpetの使い方として、Markdownの文章をredcarpetのインスタンスに流し込むとHTMLが生成されます。

そして、Markdownと言っても、記述の仕方などオプションがあるため、インスタンスの作成の際には、そのオプションについても設定する必要があります。

実際に使う場合、インスタンスの生成はhelper内にメソッドで記述します。私の場合、app/helper/application_helper.rb内に記述しました。

module ApplicationHelper
  def markdown(text)
    render_options = {
      filter_html: true,
      hard_wrap: true
    }

    extensions = {
      autolink: true,
      fenced_code_blocks: true,
      lax_spacing: true,
      no_intra_emphasis: true,
      strikethrough: true,
      superscript: true,
      tables: true
    }

    renderer = RougeConfig::RougeRender.new(render_options)
    Redcarpet::Markdown.new(renderer, extensions).render(text)
  end
end

render_optionsextensionsは、redcarpetで生成するHTMLの設定の記述です。

それらの設定を元に、Redcarpet::Markdown.new(renderer, extensions).render(text)のようにして、HTMLを生成します。

生成の前に、RougeRenderというクラスのインスタンスを作成していますが、これはシンタックスハイライトのための設定で、あとで詳しくで説明します。

設定

render_optionsで設定している内容は次のものです。

設定名 意味
filter_html 入力されたHTMLをエスケープする
hard_wrap Markdown内の改行をHTMLの改行にする

extensionsで設定している内容は次のものです。

設定名 意味
autolink URLの記述をリンクとして表示する
fenced_code_blocks フェンス・コードブロックの記述を可能にする
lax_spacing HTMLブロックはMarkdown標準のように空行で囲む必要はない
no_intra_emphasis foo_bar_bazのような文字列の時に強調しない
strikethrough 2つの~で囲まれたものを取り消し線とする
superscript 文字列の後に^を使って上付き文字を記述できるようにする
tables テーブルを記述できるようにする

ここで紹介しているもの以外にも設定はあり、それらはGitHubのredcarpetのリポジトリのREADME.mdで説明されているので、そちらを見てください。

vmg/redcarpet

シンタックスハイライト

シンタックスハイライトのために、rougeというGemを使っています。

rougeは、redcarpetのインスタンスの作成の際にレンダラーとして組み込む必要があり、それはrenderer = RougeConfig::RougeRender.new(render_options)という部分でレンダラーを作成しています。

このランダラーのためのクラスは、Redcarpet::Render::HTMLを継承した自作のクラスで、継承したクラス内でRouge::Plugins::Redcarpetをインクルードする必要があります。

このクラスの記述は、libディレクトリ内に作成してそこから読み込みます。

なので、lib/rouge_configという場所にrouge_render.rbという名前でクラスを記述します。

require 'redcarpet'
require 'rouge'
require 'rouge/plugins/redcarpet'

module RougeConfig
  class RougeRender < Redcarpet::Render::HTML
    include Rouge::Plugins::Redcarpet
  end
end

そして、このファイルを読み込むようにconfig/application.rbのApplicationクラス内に次の1行を追記します。

config.autoload_paths += %W(#{config.root}/lib/)

Railsの設定を変更したので、サーバを立ち上げている場合は、再起動する必要があります。

rougeでシンタックスハイライトができる言語は、次のサイトから確認できます。

Rouge

スタイル

シンタックスハイライトのためには、対応するテーマを追加する必要があります。

テーマはapp/assets/stylesheets内にrouge.css.erbのような名前でファイルを作成し、そのファイル内で次のように記述します。

<%= Rouge::Themes::Monokai.render(:scope => '.highlight') %>

ここでは、Monokaiというテーマで色を付けています。

rougeには、あらかじめいくつかのテーマが用意されており、そのテーマは次で確認できます。

rouge/lib/rouge/themes/

HTMLに変換

実際に、Markdwonの文章をHTMLに変換するには、Viewファイルなどで、次のようにhelper内のメソッドを呼び出します。

<%= sanitize markdown(text) %>

textには、Markdown形式で書かれた文章が代入されているとします。

このように、helper内のメソッドを呼び出すとHTMLが戻り値となるので、それをsanitizeメソッドでHTMLがエスケープされないようにします。

もしsanitizeメソッドを使わないと、せっかくredcarpetでHTMLが生成されたのに、それが全てエスケープされてしまい正しく表示されなくなります。

まとめ

やってみるとかなり簡単にできると思います。

redcarpetには設定できる項目がたくさんあるので、状況に応じて使い分けましょう。