はじめに
どうも、Pirikaraです。
今回は適当に作った○witterもどきのアプリで、ハッシュタグ機能を実装してみたので共有したいと思います。
まずはrails new
まずはT○itterもどきのアプリを作ります。
tag機能を実装するので、rails newでtag_appを作ります(適当)
tweetモデルとtagモデルを作成しますが、
両者は多対多の関係なので、中間テーブルとしてtweet_tagモデルも作っておきます。
class Tweet < ApplicationRecord
has_many :tweet_tags
has_many :tags, through: :tweet_tags
#写真の投稿も可能にするために、carrierwaveとminimagickを入れておいた
mount_uploader :image, ImageUploader
end
class Tag < ApplicationRecord
has_many :tweet_tags
has_many :tweets, through: :tweet_tags
end
class TweetTag < ApplicationRecord
belongs_to :tweet
belongs_to :tag
end
まずはImageとTextのみ投稿ができるTw○tterもどきアプリを作りました。
class TweetsController < ApplicationController
def index
@tweets = Tweet.all
end
def new
@tweet = Tweet.new
end
def create
tweet = Tweet.create(tweet_params)
redirect_to tweets_path
end
private
def tweet_params
params.require(:tweet).permit(:image, :text, :tag_ids)
end
end
現在『Tags』のプルダウンには何も入っていませんが、Tagsテーブルに登録されているものが表示される仕様です。
今回はtextarea内に『#(ハッシュタグ)』があれば、それ以下をtagとして認識、Tagsテーブルに保存される形でコードを書いていきたいと思います。
仕様と進め方の確認
- textareaに『#(ハッシュタグ)』があれば『#』以下をtagとして認識し、Tagsテーブルに保存する
- 一覧表示画面にて、tag名が『#○○○』の形で表示される
- 新規投稿画面にて、Tagsのプルダウンにこれまで登録されたTagが表示される。
今回はtweets_controllerのcreateアクションでTweet.createされたあと、
model/tweet.rbでActiveRecordの『after_create』というコールバックを使用し、データベースに保存される直前にTagsテーブルに『#』タグ以下を登録させる感じでやっていきます。
after_create等のコールバックについては、下記のサイトを参考にしました。
それではいざ、実装。
Tweet Modelにコールバックの記述
after_create do 〜 endの間に処理を記述していきます。
1. controller側でcreateしたTweetを取得
2. Tweetのtextカラムの値から、『#〇〇〇』に該当する箇所を検出
3. tagsテーブルに保存
加えて、view側で『#〇〇〇』をtagsテーブル経由で表示させまます。
4.『#〇〇〇』を含む形でtweetsテーブルに保存されているので、viewで出力する際に正規表現を使って取り除く。
コードは以下の通りです。
class Tweet < ApplicationRecord
has_many :tweet_tags
has_many :tags, through: :tweet_tags
mount_uploader :image, ImageUploader
#DBへのコミット直前に実行
after_create do
#1.controller側でcreateしたTweetを取得
tweet = Tweet.find_by(id: self.id)
#2.正規表現を用いて、Tweetのtext内から『#○○○』の文字列を検出
tags = self.text.scan(/[##][\w\p{Han}ぁ-ヶヲ-゚ー]+/)
#3.mapメソッドでtags配列の要素一つ一つを取り出して、先頭の#を取り除いてDBへ保存する
tags.uniq.map do |t|
tag = Tag.find_or_create_by(name: t.downcase.delete('#'))
tweet.tags << tag
end
end
end
<div class="content">
<% @tweets.each do |tweet| %>
<div class="content__post">
<%=image_tag "#{tweet.image}"%>
<div class="content__post__tags">
<!--4.gsub()で正規表現に合致する箇所を空欄にする-->
<%= simple_format(tweet.text.gsub!(/[##][\w\p{Han}ぁ-ヶヲ-゚ー]+/, "")) %>
<!--4.tweetにタグがあればタグを出力する-->
<% if tweet.tags.any? %>
<% tweet.tags.each do |tag| %>
<p>#<%= tag.name %></p>
<% end %>
<% end %>
</div>
</div>
<% end %>
</div>
<div class="footer">
</div>
index view側でハッシュタグとともにtweetを表示させることができました。
DBにもちゃんと保存されていますね。
めでたしめでたし。
おわりに
今回はTwitte○もどきのアプリでハッシュタグ機能の実装にチャレンジしてみました。
View側で表示させる時に正規表現を使っているところが不恰好なのでヘルパーに突っ込んでもいいかもしれませんね。
応用としては、ハッシュタグからリンクを飛ばして紐づいたtweetを一覧表示できる・・・・・・とかですかね。
ぜひチャレンジしてみてください。
おわり。