Rails
Markdown
redcarpet

[Rails] redcarpetを使ったマークダウンのHTML書き出しタグをカスタマイズする

先に結論

Redcarpet::Render::HTMLを継承したカスタム用Rendererクラスを作って必要なタグを上書きします。

highlightのときのタグを変更したい

デフォルトでは==で囲うと<mark>タグでrenderされます。
例えばこれを赤文字にしたい場合で、CSSの構成上、markに対してスタイルを宣言するのではなく、赤文字にするclassをあてたいということがあると思います。
このような場合、テキストを囲うだけのタグなら

# application_helper.rbなど
def markdown(text)
  markdown = Redcarpet::Markdown.new(MyRenderer)
end

# 適当な場所(lib以下とか)
class MyRenderer < Redcarpet::Render::HTML
  def highlight(text)
    %(<mark class="text-danger">#{text}</mark>)
  end
end

# index.html.slimなど
== markdown("==ほげほげ==")
#-> <mark class='text-danger'>ほげほげ</mark>

こんな感じでできます。
同じようにemphasisとかunderlineとかもカスタマイズできると思います。
インライン要素のタグを生成するメソッド名はこちらを参照してください。

list item

ul>liとかol>liにclassを付けたい!ときにREADMEにヒントがなくてちょっと困ったんですが、わりとシンプルでした。

def list_item(text, list_type)
  case list_type
  when :ordered
    %(<li class="list-ordered">#{text}</li>)
  when :unordered
    %(<li class="list-circle">#{text}</li>)
  end
end

list

ul / ol 自体をカスタマイズしたい!なら

def list(contents, list_type)
  case list_type
  when :ordered
    %(<ol class="ordered-list">#{contents}</ol>)
  when :unordered
    %(<ul class="circle-list">#{contents}</ul>)
  end
end

簡単ですね!

背景

ECサイトのコンテンツを運用していて、例えば商品情報の追加・更新をエンジニアではなく運用チームがやります。
そのとき、商品の詳細内容などを運用チームに入れてもらうのですが、商品によって「赤文字にしたい」「ここは太字にしたい」「文字を大きくしたい」など要件があるので、プレーンテキストというわけにはいかず、かといって、HTMLを書いてもらうことに抵抗がありました。

HTML🙅な理由としては

  • HTMLに慣れていない非エンジニアだと簡単にタグのとじ漏れとかが発生する
  • できることが多すぎて煩雑な(某®的な)画面になるリスク
  • 赤文字にする等でclassを使わないといけない場合、スタイルシートの刷新とかCSSフレームワークを変更するときにテーブルの中で文字列検索・置換などしないといけなくなる

みたいなところです。

そこで、マークダウンで運用してもらって、HTMLに変換するときにアプリケーション側で必要なclass名等をカスタマイズしてあげるという方法がよいのではとなりました。
(社内でドキュメントの共有にDocbaseを使っていて、運用チームもマークダウンには親しみがある)

マークダウンのパーサーを自前で作るのは大変だなーと直感的に思ったので、Railsアプリケーションだしいい感じのGemがあるかなーと調べたら、redcarpetというGemでできそうだなとなったので、カスタマイズを試してみました。

よさそう

わりと簡単にカスタマイズできたし、これならば、例えば場所によって見せ方を変えたいときにもその場所毎にrendererを用意すれば対応できて良さそうと思いました。
コンテンツは同じだけど、Aページではリンクを有効にしてBページではリンクさせないで太字にする、とか。

※環境はRuby2.3.0/Rails4.2.6/redcarpet3.4.0です。