Ruby
Rails

[html-pipeline]テキストデータを加工して、HTMLで安全に出力する方法

More than 1 year has passed since last update.


概要

先日、html-pipelineのgemを使う機会があったので、備忘録も兼ねて、

本gemの使い方について、書いていきたいと思います。(´ε`)

使い方は簡単なんですが、日本語の解説ページがあんまり無かったので、掲載(^o^)/

Webフォーム等から入力されたテキストデータをサニタイズ(タグのエスケープや削除とか)し、

ちょっと加工して、HTMLとして表示させたい場合があると思います。

- CMS的なサイトでフォームでコンテンツを入力させて、Webページとして表示させたい

- http://〜〜のリンクがあったらハイパーリンクで表示したい

- タグ等は文字として表示させたい

- Youtubeとかのリンクがあったら、埋め込みのような形で表示したい

こんなことをやってくれるのがgem html-pipeline です。

https://github.com/jch/html-pipeline


環境

Rails 5.0.1

Ruby 2.3.1


html-pipelineで何ができるのさ?

冒頭にも書きましたが、html-pipelineを使うことで、

テキストデータを加工して、html出力することができます。

html-pipelineには「フィルター」という概念があり、例えば、

「http://〜をリンクとして表示したいな」と思ったら、そのフィルターを設定することで、

テキストデータの中から文字列を見つけて、aタグで囲んでくれたりします。

フィルターの種類はgithubのページに記載されていますが、例として以下のようなフィルターがあります。

リンク作ったり、マークダウンをhtmlにしたり、youtubeの埋め込みタグ作ったりです。

例えば、httpはリンクにして、youtubeへのリンクは埋め込んで表示させたいなら、フィルターを2つを指定します。

(gitbubのページから一部抜粋) 

MentionFilter - replace @user mentions with links
AutolinkFilter - auto_linking urls in HTML
EmojiFilter - everyone loves emoji!
MarkdownFilter - convert markdown to html
PlainTextInputFilter - html escape text and wrap the result in a div
html-pipeline-nico_link - An HTML::Pipeline filter for niconico description links
html-pipeline-youtube - An HTML::Pipeline filter for YouTube links


使い方

1.ベースとなるhtml-pipelineのインストール

githubのinstallationに書いてあります。

Genfileに

gem 'html-pipeline'

を入れて、

$ bundle install

2.フィルターの選定

どのフィルターを使うか選びましょう。

Githubの「Filters」または「3rd Party Extensions」からチョイスします。

3.依存関係のあるgemのインストール

まず、Filtersの中からフィルターを選択したあなた!

あなたが選択したフィルターを動作させるためには別途gemが必要かもしれません。

依存関係のあるgemは、「Dependencies」の章に書いてあります。

例えば、httpをリンクして表示したいなら、「AutolinkFilter」が必要で、

これを動作させるためには「rinku」というgemが別途必要です。

こんな感じで書いてありますね。

AutolinkFilter - rinku

また、依存関係のgemにはバージョンが指定されているものがあります!

以下のリンク先をチェックして、gemをインストールしましょう。

Note: See Gemfile :test block for version requirements.

そして、3rd Party Extensionsからフィルターを選択したあなた!

別途gemを入れる必要があります。リンク先に飛んでgemを入れましょう!

例えば、「html-pipeline-youtube」を選択した場合、

html-pipeline-youtube

というgemをインストールします。

4.では使いましょう

使い方は簡単です。

1)html-pipelineのインスタンス生成

2)生成したインスタンスの引数にテキストを与える

  3)テキストが出力されるのでhtml_safeとかしてviewで表示

以上!w

少し詳しく書いていきます。

1.html-pipelineのインスタンス生成

HTML:Pipeline.newでインスタンスを生成しますが、その際に引数を2つ(a,b)与えます。

  a:配列で適用するフィルターを記載

  b:フィルターが必要なオプションをハッシュで指定

実際のコードはこんな感じ↓です。以下の例では2つのフィルターを定義しています。

bの引数は、AutolinkFilterのオプションです。

必要/設定可能なオプションは、「/lib/html/pipeline/」以下の[フィルター名.rb]に書かれています。

HtmlSanitizationPipeline = 

HTML::Pipeline.new [
HTML::Pipeline::YoutubeFilter,  # aの適用フィルター
HTML::Pipeline::AutolinkFilter
], {autolink: true, link_attr: 'target="_blank"'} # bのフィルターオプション

2.生成したインスタンスの引数にテキストを与える

以下のような感じでcallメソッドの引数としてテキストデータを与えます。

返り値のハッシュのoutputに結果が入りますので、それを出力すればOKです。

これらをヘルパーメソッドにして、viewから呼んであげれば色々使いまわせます。

result = HtmlSanitizationPipeline.call(テキストデータ)

result[:output].html_safe


html-pipeline + 別メソッドで要件にあったものを

基本的な使い方は以上ですが、上記の例ではタグなどに囲まれた文字は、

文字として出力されず削除されてしまうと思います。

文字として出力するための(文字エスケープ)フィルターとしてhtml-pipelineには、

PlainTextInputFilter - html escape text and wrap the result in a div

が用意されていますが、今回これは使いませんでした。(微妙に出力結果が要件に合わず)

先日html-pipelineを使った際には、pipelineに渡す前にrailsのhtml_escapeメソッドで

タグ等をエスケープ処理した上で、pipelineにデータを渡す方法を選択しました。

result = HtmlSanitizationPipeline.call(html_escape(テキストデータ))

result[:output].html_safe

要件によってはresultに対してさらに加工が必要なこともありますが、その場合は、

split_paragraphsで行単位で処理するとか、railsのメソッドと組合せるとお手軽にできるかもです。

ではでは〜〜\(^o^)/