Railsでハッシュタグ機能を実装してみた(gemなし) 後半

# 概要
前半ではRouteの作成とハッシュタグ別のViewを作成する手前まで書きましたが、その続きを書いています。
具体的には、

* Routeの作成
* ハッシュタグコントローラーを作成
* ハッシュタグ別の投稿一覧を表示するView


上記の実装を後半でやっていきます。
まだ前半を見てらっしゃらない方は、下記のリンクからご覧ください。
https://qiita.com/Prog_taro/items/9dc5fe39eb6149acabd4

# Routeを作成

```config/routes.rb
get '/post/hashtag/:label_name', to: 'hashtags#index'
```

あまり日本語でURLを作るべきではないと思うのですが、今回はわかりやすくするためにタグの名前でURLを作成する事にしました。

# ハッシュタグコントローラーを作成

```
$ touch app/controllers/hashtags_controller.rb
```
もちろん rails g コマンドで作成しても良いですが、今回は素直に作成しました。

# ハッシュタグコントローラーを編集

```app/controllers/hashtags_controller.rb
class HashtagsController < ApplicationController
  before_action :authenticate_user!
  def index
    @label = params[:label_name]
    hashtag = Hashtag.find_by(label: @label)
    if hashtag.nil?
      redirect_to root_path, alert: "##{@label}のタグがついた投稿は存在しません"
    else
      @posts = hashtag.posts.includes(:photos, :user, :likes, :comments).recent
    end
  end
end
```

上記のコードを説明させていただきます。

```app/controllers/hashtags_controller.rb
before_action :authenticate_user!
```
これはログインしているユーザーしかこのページを見られないようにするためのメソッドです。
deviseというGemを入れないと使えません。
僕の場合、入れているので使用することができます。
アプリの設計上、ログインしているユーザーにしか見れないようにしたかったので導入しました。

```app/controllers/hashtags_controller.rb
@label = params[:label_name]
```
クリックしたハッシュタグをビュー側にも表示させたいという意図があったためインスタンス変数にパラメータで渡ってきた:label_nameを入れています。

```app/controllers/hashtags_controller.rb
hashtag = Hashtag.find_by(label: @label)
```
このコードはハッシュタグの名前がパラメータで渡ってきた名前と同一のもの、つまり、DBに登録されているハッシュタグの中から該当のハッシュタグを取り出しているコードです。

例えばパラメータで "こんにちは" というものが送られてきたら、DBに登録されているハッシュタグから "こんにちは" と同一のものを取り出すということです。

なぜ同一のものを取り出せるのかというと、前半部分を書いた記事でハッシュタグはuniqにしているからです。

```app/controllers/hashtags_controller.rb
if hashtag.nil?
  redirect_to root_path, alert: "##{@label}のタグがついた投稿は存在しません"
else
  @posts = hashtag.posts.includes(:photos, :user, :likes, :comments).recent
end
```

この部分は先ほど書いたfind_byで該当ハッシュタグがない状態、つまりNilのことを許容しているのですが、Nilだった場合にエラーにならないよう書いている部分です。
find_byがNilを許容していることについては下記をご覧ください。
https://railsdoc.com/page/find_by

else の中身について説明します。

```app/controllers/hashtags_controller.rb
@posts = hashtag.posts.includes(:photos, :user, :likes, :comments).recent
```

後ほどViewでも使う予定なのでインスタンス変数に入れています。
hashtag.postsとするだけでも該当ハッシュタグがついた投稿一覧が出るのですが、N+1問題が発生しているので .includs をつけています。

N+1問題についてものすごく簡潔に説明すると、DBにアクセスする回数が多くなれば多くなるほど接続に時間がかかってパフォーマンスが落ちる！という感じでしょうか。
(僕も初心者なので詳しくはしっかりと調べてみることをお勧めします)
もっと詳しく知りたい方は良い記事がありますので、下記を参照してください。
https://qiita.com/TsubasaTakagi/items/8c3f4317ad917924b860

一番最後の .recent は .order をscopeにしてまとめたものです。

# Postモデルに追加

```app/models/post.rb
scope :recent, -> { order(created_at: :desc) }
```
基本的にorderはスコープにしてまとめた方が良さそうですね。

# Viewを作成

いよいよハッシュタグ別のViewを作成するんですが、僕はもともとあった投稿一覧画面をそのまま引用しました。
特別にそのページだけ仕様を変えたい場合は変えるべきですが、僕の場合はそのまま利用したのでここでの詳しいご紹介は割愛させていただこうと思います。
皆さんも特別何か変更を加えるつもりがない場合は、使用している変数などを変更した上で、再利用しても良いと思います。

変更した場所のみ簡潔にまとめさせていただこうと思います。

```app/views/hashtags/index.html.erb
<h2 class="text-center text-secondary mt-5"><%= "#" + @label %>のタグを含む投稿一覧</h2>
```
Bootstrapを使用しているのでclassを付与しています。
先ほどインスタンス変数に入れた該当ハッシュタグの名前を表示させました。
こうする事によって、ユーザー目線でよりわかりやすくなるのではという意図です。

```app/views/hashtags/index.html.erb
<% @posts.each do |post| %>

....中身は省略....

<% end %>
```
投稿知覧を表示するためにeachを使っていたのですが、元の変数を先ほどインスタンス変数に入れた該当タグの全投稿に変えました。

僕が変更したのはこれぐらいです...笑
ユーザー目線で考えると、チラチラ画面が変わってたら目が疲れるかな？という意図でわざとあまり変更は加えませんでした。

# 最後に...

初心者なりに書いて見ました！参考になった方が1人でもいらっしゃれば幸せです。
アウトプットにもなりましたし、またテーマを思いついたら書いてみようと思います。

間違っている部分などがありましたら、ご指摘いただければ加筆修正させていただきますのでお願いします！

ここまで読んでいただいて本当にありがとうございました。