🐦
RailsでTwitter風のハッシュタグ機能を実装してみる
はじめに
Twitter のようなハッシュタグ機能を Rails を使って実装してみます。
本記事では Rails Tutorial の Sample apps をベースにハッシュタグ機能を追加しています。
ハッシュタグ機能の実装
routing の追加
パラメータで渡されたハッシュタグに一致する投稿を検索する場所として、search アクションを追加します。
routes.rb
resources :microposts, only: [:create, :destroy] do
collection do
get :search
end
end
ハッシュタグの抽出・リンク化
次に投稿に含まれるハッシュタグを抽出してリンクにする処理を追加します。
ハッシュタグの抽出は正規表現を使っています。
抽出条件は以下のようにしました。(Twitter のハッシュタグはもっと複雑だと思いますが、今回は簡易にしました。正規表現は苦手なのでこれが限界でした。)
-
#
が先頭 or 空白文字の後 or 全角空白の後 にあること -
#
の後に 1 文字以上続くこと -
#
は最後 or 空白文字 or 全角空白 で終わること
microposts_helper.rb
module MicropostsHelper
HASHTAG_REGEX = /(?<=\s| |^)#.+?(?=( |\s|$))/.freeze
def link_to_hashtag(content)
content.gsub(HASHTAG_REGEX) { |hashtag| link_to(hashtag, search_microposts_path(q: hashtag)) }
end
end
View に表示できるようにする
上で追加したlink_to_hashtag
を View で使っても以下のようにエスケープされてリンクにはなりません。
ですので、一手間加えます。html_with_link_to_hashtag
というメソッドを追加しています。
microposts_helper.rb
module MicropostsHelper
HASHTAG_REGEX = /(?<=\s| |^)#.+?(?=( |\s|$))/.freeze
def link_to_hashtag(content)
content.gsub(HASHTAG_REGEX) { |hashtag| link_to(hashtag, search_microposts_path(q: hashtag)) }
end
def html_with_link_to_hashtag(content)
# 下の処理でaタグのhref属性を表示できるようにするので、ハッシュタグのaタグ以外が有効にならないように、エスケープしておく。
html_escaped_content = h(content)
content_with_hashtags = link_to_hashtag(html_escaped_content)
# aタグのhref属性以外はサニタイズします。
# aタグのhref属性はエスケープされずに表示されるようになります。
sanitize content_with_hashtags, tags: ['a'], attributes: ['href']
end
end
_micropost.html.erb
<%= html_with_link_to_hashtag(micropost.content) %>
これでハッシュタグのリンクだけが有効な状態で表示されます。
ハッシュタグを検索できるようにする
最後にハッシュタグを使って検索できるようにします。
最初に追加した search アクションに検索する処理を追加します。
microposts_controller.rb
def search
@microposts = Micropost.search_content_for(params[:q]).paginate(page: params[:page])
end
micropost.rb
scope :search_content_for, ->(query) { where('content like ?', "%#{query}%") }
search.html.erb
<div>
<ol class="microposts">
<%= render @microposts %>
</ol>
<%= will_paginate @microposts %>
</div>
これで完成です!
※見た目は適当です…!
あとがき
-
本記事では自前で実装してみましたが、twitter-text という gem があったので、ハッシュタグの抽出・リンク化はこれを使ってみても良さそうでした。
-
セキュリティを考慮して
html_with_link_to_hashtag
でエスケープ・サニタイズをしていますが、もう少しスッキリした処理にしたい気持ちです。 🤔
Discussion