テキスト内のURLをリンク化する(Rails 総復習1ヶ月チャレンジ 10日目(番外編))

追記

こちらはある一定条件でバグが発生することが判明したので、修正版を下記記事に記載しております。

(更新版)テキスト内のURLをリンク化する(Rails 総復習1ヶ月チャレンジ 14日目(番外編)) - yama2_0506’s diary

こんにちは!こんばんは!チャレンジ10日目です!
気づけばまたしても記事が1日空いてしまいました・・・反省
ということでまた気合い入れていきます!
今日はお手伝いさせてもらっている開発でテキスト内にユーザーがURLを入力した際に自動でリンク化させる機能を実装させてもらったのでそれを復習します。

コード全文

#app/helpers/application_helper.rb

 def text_url_to_link(text)
   require 'uri'
   URI.extract(text, ['http', 'https']).uniq.each do |url|
     sub_text = "<a href=#{url} target=\'_blank\'>#{url}</a>"
     text.gsub!(url, sub_text)
   end
   return text
 end
#Viewファイル内

 <%== simple_format(text_url_to_link(@user.description), {}, sanitize: false) %>

text_url_to_linkメソッド

一つずつ紐解きます。

 require 'uri'

Rubyの標準のライブラリとしてURIを楽に取得出来るものです。なお今回メソッド内に定義しているのは現状このメソッド以外の他メソッドでは使用していないので分かりやすくしている為です。

URI(Uniform Resource Identifier)とは・・・URLとURNを総称したもの。
URL(Uniform Resource Locator)・・・Web上にあるファイルの位置を示している。Web上の住所のようなもの。
URN(Uniform Resource Name)・・・Web上でのファイルの名前。識別するための番号やシリアルナンバーのようなもの。
参考: Rubyのuriライブラリの使い方を現役エンジニアが解説【初心者向け】
module URI

URI.extract(text, ['http', 'https']).uniq.each do |url|

URI.extract(str)・・・引数に渡した文字列にURIが含まれていればマッチした文字列からなる配列を返す。
第2引数に検索の対象としたいスキームを文字列の配列として与えると、そのスキームだけを検索します。 これを踏まえた流れは、URI.extractの第一引数textに第二引数のスキーム名"http","https"を含むURLを検索し、uniqで重複を削除したのちブロック内のurlに渡します。

参考: singleton method URI.extract

sub_text = "<a href=#{url} target=\'_blank\'>#{url}</a>"
text.gsub!(url, sub_text)

ブロック内ではsub_textというローカル変数にリンクとする為のaタグを生成する文字列を代入しています。 text.gsub!でレシーバー自身のurlに入った文字列をaタグリンクの文字列に置き換えています。

return text 

最終的に、return textで「URLをaタグに置き換えたテキスト(text)」を返します。

Viewでの呼び出し

次にView部分dです。

まずこの部分

 <%==

これはRailsでデフォルトで行われるエスケープ処理を行わせたいくないので実装しています。なお同様の処理をしてくれるrawやhtml_safeメソッドもあるのですが、今回はhtml_safeの場合はnilの場合に例外となってしまうらしく、かつrawより<%==の方が若干内部処理が早い?とのことでこちらを採用しています。

参考: Active Support Core Extensions — Ruby on Rails Guides

[Ruby On Rails]HTMLのエスケープ回避(raw, │ もっこすばっこす

エスケープについてはこちら参照
エスケープ処理(escape processing)とは - IT用語辞典 e-Words

text_url_to_link(@user.description)

application_helper内で作成したtext_url_to_linkメソッドを呼び出しています。

 {}, sanitize: false

今回はsimple_formatを使っており、その中でtarget='_blank'が効かずに苦戦しました。

simple_formatについてはこちら
simple_format | Railsドキュメント

調べてみるとsimple_formatでtarget属性が取り除かれている?ようです。その為、simple_format内でsanitize: falseを付けることによりtarget=_'blank'を反映させるようにしています。

参考: ruby on rails - simple_format is stripping out target _blank - Stack Overflow

simple_format (ActionView::Helpers::TextHelper) - APIdock

今回は以上です!