概要
ハッシュタグ機能を実装する方法をまとめます。
参照
https://glodia.jp/blog/3936/
https://qiita.com/Naoki1126/items/4ea584a4c149d3ad5472
これら2つの記事の情報を組み合わせて実装しました。
ありがとうございます。
完成イメージ
今回は、写真投稿アプリを題材に、写真のキャプションにハッシュタグを導入する方法を説明します。
写真詳細画面のキャプションにリンク付きハッシュタグが記載され、クリックするとそのハッシュタグのページが表示される。
#開発環境
- macOS Catalina 10.15.7
- ruby 2.6.5
- Rails 6.0.3.4
実装の流れ
- 各種モデルとマイグレーションファイルを準備
- ハッシュタグ保存・更新アクションをモデルに追加
- ルーティングを設定
- ヘルパーメソッドを作成
- コントローラーにhashtagアクションを作成
- ビューの編集
今回のコード
コードは、必要な部分以外は省略して記載します。
1. 各種モデルとマイグレーションファイルを準備
hashtagモデルを作成
%rails g model hashtag
中間テーブルを作成
%rails g model photo_hashtag_relation
マイグレーションファイルを編集
テーブルのカラムを設定します。
class CreateHashtags < ActiveRecord::Migration[6.0]
def change
create_table :hashtags do |t|
t.string :hashname
t.timestamps
end
add_index :hashtags, :hashname, unique: true
end
end
class CreatePhotoHashtagRelations < ActiveRecord::Migration[6.0]
def change
create_table :photo_hashtag_relations do |t|
t.references :photo, index: true, foreign_key: true
t.references :hashtag, index: true, foreign_key: true
t.timestamps
end
end
end
モデルを編集
バリデーションとアソシエーションを設定します。
class Hashtag < ApplicationRecord
validates :hashname, presence: true, length: { maximum:99}
has_many :photo_hashtag_relations
has_many :photos, through: :photo_hashtag_relations
end
class PhotoHashtagRelation < ApplicationRecord
belongs_to :photo
belongs_to :hashtag
with_options presence: true do
validates :photo_id
validates :hashtag_id
end
end
マイグレート
%rails db:migrate
2. ハッシュタグ保存・更新アクションをモデルに追加
photoモデルに以下のコードを追加します。
これで、写真投稿(create)、編集(update)時にハッシュタグがhashtagsテーブルに保存されます。
# 省略
has_many :photo_hashtag_relations
has_many :hashtags, through: :photo_hashtag_relations
.
.
# 省略
.
.
#DBへのコミット直前に実施する
after_create do
photo = Photo.find_by(id: self.id)
hashtags = self.caption.scan(/[##][\w\p{Han}ぁ-ヶヲ-゚ー]+/)
photo.hashtags = []
hashtags.uniq.map do |hashtag|
#ハッシュタグは先頭の'#'を外した上で保存
tag = Hashtag.find_or_create_by(hashname: hashtag.downcase.delete('#'))
photo.hashtags << tag
end
end
before_update do
photo = Photo.find_by(id: self.id)
photo.hashtags.clear
hashtags = self.caption.scan(/[##][\w\p{Han}ぁ-ヶヲ-゚ー]+/)
hashtags.uniq.map do |hashtag|
tag = Hashtag.find_or_create_by(hashname: hashtag.downcase.delete('#'))
photo.hashtags << tag
end
end
end
ルーティングを設定
photosコントローラーにhashtagアクションを定義し、getで各ハッシュタグのページを表示させます。
URLは末尾にハッシュタグ名が来るようにしました。
:name
に入る値はこの後ヘルパーメソッドで設定します。
例えば、#カメというハッシュタグだとURLは
.../photo/hashtag/カメ
となります。
get '/photo/hashtag/:name', to: "photos#hashtag"
ヘルパーメソッドを作成
photos_helper.rbに以下のコードを記載します。
photos_helper.rbファイルがない場合は自分で作成します。
helperについては、https://www.sejuku.net/blog/28563 などを参照
このヘルパーメソッド使用により、リンク付きのハッシュタグが入ったキャプションが作成されます。
コード内では、ハッシュタグ名が末尾に入ったURLが作成され、ハッシュタグクリック時のリンク先として設定されています。
ハッシュタグ名の前のURLには、先程route.rbに書いたURLを書き込みます。
module PhotosHelper
def render_with_hashtags(caption)
caption.gsub(/[##][\w\p{Han}ぁ-ヶヲ-゚ー]+/){|word| link_to word, "/photo/hashtag/#{word.delete("#")}"}.html_safe
end
end
コントローラーにhashtagアクションを作成
ハッシュタグに紐付いた写真を@photosに代入し、hashtagビューで使用し表示させます。
def hashtag
@user = current_user
@tag = Hashtag.find_by(hashname: params[:name])
@photos = @tag.photos
end
ビューの編集
先程作成したヘルパーメソッドrender_with_hashtags
を記載することにより、リンク付きハッシュタグが記載されたキャプションを写真詳細画面に表示させます。
# 省略
<%= render_with_hashtags(@photo.caption) %>
ハッシュタグ画面では、hashtagアクションで設定した@photos
を取り込み、ハッシュタグに紐づく写真を1枚ずつ表示させます。
<h2>ハッシュタグ #<%= @tag.hashname %></h2>
<ul>
<% @photos.each do |photo| %>
<li>
<%= link_to photo_path(photo.id) do %>
<%= image_tag photo.image.variant(gravity: :center, resize:"640x640^", crop:"640x640+0+0"), if photo.image.attached? %>
<% end %>
</li>
<% end %>
</ul>
おわりに
以上が、今回行ったハッシュタグ機能実装の方法です。
意味が理解できていないコードが多々ありますが、追々理解していければと思います。
初学者なので間違いがありましたら、ご指摘いただきたいですm(_ _)m