RailsでMarkdown記法に対応したビューをつくる(Redcarpet + Rouge)

Rails初心者です。(重い腰をあげての)Qiita初投稿のため、不足点や改善点あれば優しくそっと教えてくださると大変ありがたいです。

現在、コーディングの練習ができるWebアプリケーションの作成をしております。そこで問題になるのが、コードの表示をどうするかということです。調べた結果、Markdown記法に対応したビューを作ればそれらしいものになると分かりました。複数の参考記事のつぎはぎで得た、自分の中でもっともシンプルな書き方を共有させていただきます。

# 結論
Markdown記法対応は「`redcarpet`」というgem
シンタックスハイライトは「`rouge`」というgem
で、シンプルに実現できる。[^1]

(XSS攻撃の標的にならないように、投稿機能に使う際は要対策:`escape_html`や`quote`オプションなど)

[^1]: 他にもMarkdown記法対応に「`Marked.js`」(gemだと`marked-rails`)、シンタックスハイライトに「`highlight.js`」を使うコンビもありましたが、古いのかgemを入れてうまく動かず...。また、シンタックスハイライトに「`coderay`」というgemを使う方法も出てきましたが、黒地に白文字系にする方法がよく分からなかったので断念。

# 流れ
1. gemを追加
2. bundle installする
3. markdown_helper.rbを作成し、コード記述
4. rouge.scss.erbを作成し、コード記述
5. ビューファイルにコード記述
6. 完成！

# 1. gemを追加
Gemfileの末尾に以下を追加します。

```:Gemfile
...
gem 'redcarpet'
gem 'rouge'
```
# 2. bundle installする
ターミナルで以下を実行。

```
bundle install
```

# 3. markdown_helper.rbを作成し、コード記述
markdownというメソッドが外から呼び出せるように、以下のように記述。なお、名前は任意でOKです。
[こちら](https://workabroad.jp/posts/2207)を参考に一部改変しました。おそらく調べた中ではもっともシンプルな書き方の一つ。

```ruby:app/helpers/markdown_helper.rb
module MarkdownHelper
  require 'rouge/plugins/redcarpet'

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

  def markdown(text)
    render_options = {
      filter_html:         true, # ユーザーが入力したhtmlを出力しない
      hard_wrap:           true, # 改行をhtmlの<br>に置き換え
      space_after_headers: true  # ヘッダー記号(#)と文字の間にスペース必要
    }
    renderer = HTML.new(render_options)
  
    extensions = {
      autolink:           true, # 自動でリンク化
      fenced_code_blocks: true, # コードを表す「```」を認識
      no_intra_emphasis:  true, # 文字の強調を無視
      strikethrough:      true, # 取り消し線を表す「~~」を認識
      superscript:        true, # 上つき文字を表す「^」を認識
      tables:             true, # テーブルを認識
      escape_html:        true, # xss対策 全てのHTMLタグをエスケープ(filter_htmlより優先) 
      quote:              true  # xss対策 引用符を表す「""」を認識
    }
    Redcarpet::Markdown.new(renderer, extensions).render(text).html_safe
  end
end
```

# 4. rouge.scss.erbを作成し、コード記述
rougeに設定されている配色を反映させるためのファイルです。部分テンプレとして読み込ませるやり方(_rouge.scss.erb)でもいけるみたいです。
`MonokaiSublime`の部分はカラーテーマを指し、他にも`Base16`や`Github`などいろんなカラーテーマがあるそうです。自分がこれを選んだのは、黒地に白文字のいわゆるコードっぽい表示になるためです。
[Rouge Theme Preview Page](https://spsarolkar.github.io/rouge-theme-preview/)

```ruby:app/assets/stylesheets/rouge.scss.erb
<%= Rouge::Themes::MonokaiSublime.render(:scope => '.highlight') %>
```

# 5. ビューファイルにコードを記述
あとはビューファイルの中でmarkdownメソッドを呼び出すだけで、引数の文字列をMarkdown形式で表示することができます。

```ruby
<%= markdown(Markdown記法で書いた文字列) %>
```

例：

```ruby

<%= markdown("# Title") %>

<%= markdown("## SubTitle") %>

<%= markdown("```ruby 
def test 
  puts 'test' 
end
```") %>

<%= markdown("---") %>

<%= markdown("[Link](URL)") %>
```

# 6. 完成！
無事にできていれば、上記の例の出力結果は以下の画像のようになっているはずです。
![test_markdown](https://gyazo.com/06c943a1a48b70270f41bd51da0492ca.png)

# まとめ
`redcarpet`と`rouge`でMarkdown記法とシンタックスハイライトに対応可能！rougeのスタイルを反映させる方法は何通りかある。XSS対策には要注意。
最後まで読んでくださりありがとうございました！

# 参考記事
公式
https://github.com/vmg/redcarpet
https://github.com/rouge-ruby/rouge

その他記事
https://www.autovice.jp/articles/40
https://workabroad.jp/posts/2207
https://qiita.com/manbolila/items/53c2b431f27f31248cd9
https://qiita.com/yuuuking/items/3f88454e164a5f7d4733
https://qiita.com/hkengo/items/978ea1874cf7e07cdbfc

XSS関連
https://snyk.io/vuln/SNYK-RUBY-REDCARPET-1059089