Railsで作ったインスタもどきのキャプションにハッシュタグを実装

#概要
Rails5でインスタもどきを作ってみたものの肝心の検索とハッシュタグが無いという未完成なものとなっていた。始業前の空き時間を使ってハッシュタグの実装をしたのでコードを貼ってみる。

#既存（Tutorial）に加えて準備する必要があるもの  
・hashtag用のテーブル
・hashtagとmicropostの中間テーブル

#完成した姿 
![完成.png](https://qiita-image-store.s3.amazonaws.com/0/146880/c26c7a81-2e34-6feb-9d90-2e3cd2fe9c89.png)
![完成2.png](https://qiita-image-store.s3.amazonaws.com/0/146880/5c45edb8-573b-7e13-1dee-bdc4a92c2c22.png)
・#記号を判断して次のスペースまでの文字列をハッシュタグとして抽出しDBに保存
・ハイパーリンク化されており、クリックするとハッシュタグのページになる

#テーブル準備
##ハッシュタグモデルの作成
```
$ rails g model Hashtag hashname:string
```
##マイグレーションファイル編集
```/db/migrate/...create_hashtags.rb
class CreateHashtags < ActiveRecord::Migration[5.2]
  def change
    create_table :hashtags do |t|
      t.string :hashname
      t.timestamps
    end
    add_index :hashtags, :hashname, unique: true
  end
end
```

##中間テーブルの作成
```
$rails g migration CreateMicropostHashtags micropost_id:references　hashtag_id:references
```
##マイグレーションファイル編集
```/db/migrate/...create_micropost_hashtags.rb
class CreateMicropostHashtags < ActiveRecord::Migration[5.2]
  def change
    create_table :hashtags_microposts, id: false  do |t|
      t.references :micropost_id, index: true, foreign_key: true
      t.references :hashtag_id, index: true, foreign_key: true
    end
  end
end
```
##マイグレーション
```
$rails db:migrate
```
#モデルの編集
##マイクロポストモデルに下記を追加
```/app/models/micropost.rb
  has_and_belongs_to_many :hashtags

  .
  .
  .

  #DBへのコミット直前に実施する
  after_create do
    micropost = Micropost.find_by(id: self.id)
    hashtags  = self.content.scan(/[#＃][\w\p{Han}ぁ-ヶｦ-ﾟー]+/)
    hashtags.uniq.map do |hashtag|
      #ハッシュタグは先頭の'#'を外した上で保存
      tag = Hashtag.find_or_create_by(hashname: hashtag.downcase.delete('#'))
      micropost.hashtags << tag
    end
  end
 
  before_update do 
    micropost = Micropost.find_by(id: self.id)
    micropost.hashtags.clear
    hashtags = self.content.scan(/[#＃][\w\p{Han}ぁ-ヶｦ-ﾟー]+/)
    hashtags.uniq.map do |hashtag|
      tag = Hashtag.find_or_create_by(hashname: hashtag.downcase.delete('#'))
      micropost.hashtags << tag
    end
  end
```
##中間テーブルモデル
```/app/models/hashtag_micropost.rb
class MicropostHashtag < ApplicationRecord
  belongs_to :micropost
  belongs_to :Hashtag
  validates  :micropost_id, presence: true
  validates  :Hashtag_id,   presence: true
end
```
##ハッシュタグモデル
```/app/models/hashtag.rb
class Hashtag < ApplicationRecord
  validates :hashname, presence: true, length: {maximum:99}
  has_and_belongs_to_many :microposts
end
```
#マイクロポストコントローラーにハッシュタグのアクションを追加
```/app/controllers/microposts_controller.rb
  def hashtag
    @user = current_user
    @tag = Hashtag.find_by(hashname: params[:name])
    @microposts = @tag.microposts.build
    @micropost  = @tag.microposts.page(params[:page])
    @comment    = Comment.new
    @comments   = @microposts.comments
  end
```
ここは少しビューの仕様が違うので人によっては不要になる宣言があるかもしれません

#マイクロポストヘルパーの編集
```/app/helpers/microposts_helper.rb
module MicropostsHelper
  def render_with_hashtags(content)
    content.gsub(/[#＃][\w\p{Han}ぁ-ヶｦ-ﾟー]+/){|word| link_to word, "/post/hashtag/#{word.delete("#")}"}.html_safe
  end 
end
```
せっかく全角にも対応しようとしたものの、deleteメソッドで複数文字を指定するやり方が分からず断念。。。  

#ルーティング
```/config/routes.rb
get '/post/hashtag/:name', to: "microposts#hashtag"
```

#ビュー
##キャプション（ハッシュタグがユーザーによって書かれるところ）
```/app/views/microposts/_micropost.html.erb
<%= render_with_hashtags(micropost.content) %>
```
##ページ遷移後のハッシュタグページ
```/app/views/microposts/hashtag.html.erb
<% provide(:title, @tag.hashname) %>
<div class="row">
  <div class="col-md-9">
    <div class="block1_hash">
       <%= image_tag("hashtag.png") %>
         <div class="block2_hash">
            <div class="name_hash">
               <%= @tag.hashname %>
            </div>
         <div class="edit_hash">
            <%= render 'users/follow_form' %>
         </div>
        <div class="fllw_hash">
          <%= render 'shared/user_info_default' %>
          <span style="margin-right:15px;"></span>
          <%= render 'shared/stats_default' %>
        </div>
       </div>
     </div>
  </div>
</div>
 
 <div class="row">
   <div class="posted_content">
     <div class="col-md-8">
       <div class="picture_hash">
         <%= render @micropost %>
       </div><!-- .picture -->
     </div>
   </div>
</div>
 ```
基本的にはユーザーページと同じデザインです。

#参考VTR
[Ruby on Rails - adding hashtags](https://www.youtube.com/watch?v=oPpigFAlLmE)

今月の社内プレゼンのネタができてよかったです。。。
この調子でがんばります。
編集箇所やアドバイス等ありましたらお気軽にお声がけくださいm(_ _)m

https://github.com/goppy001/gotostagram