つぶやきアプリを作ってみよう13

最後にいいね機能を追加しましょう。

Likeモデルを作っていきます。
「どのユーザー」が「どの投稿」をいいねしたかを記録するために、
データベースに「user_id」と「post_id」2つのカラムを持つ
likesテーブルを作成します。

##まず、モデルとマイグレーションファイルを作成します

```
rails g model like user_id:integer tweet_id:integer

rails db:migrate
```

likesテーブルにinteger型のuser_idカラムとtweet_idカラムを作成します。

モデル間のアソシエーションを組みます。

```rb:Userモデル
class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

  has_many :tweets, dependent: :destroy
  has_many :comments, dependent: :destroy  # commentsテーブルとのアソシエーション
  has_many :likes, dependent: :destroy
end

```

```rb:Tweetモデル
class Tweet < ApplicationRecord
  has_one_attached :image
  
  validates :text, presence: true, unless: :was_attached?
  def was_attached?
    self.image.attached?
  end
  validates :text, presence: true
  belongs_to :user
  has_many :comments, dependent: :destroy  
  has_many :likes, dependent: :destroy
  def self.search(search)
    if search != ""
      Tweet.where('text LIKE(?)', "%#{search}%")
    else
      Tweet.all
    end
  end
end

```

```rb:Likeモデル
class Like < ApplicationRecord
  belongs_to :user
  belongs_to :tweet
end
```


ルーティングを設定します。

```config/routes.rb
Rails.application.routes.draw do
  devise_for :users
  root to: 'tweets#index'
  resources :tweets do
    resources :comments, only: :create
    resources :likes, only: :create
    collection do
      get 'search'
    end
  end
  resources :users, only: :show
end
```

##コントローラーを作成しましょう

```
rails g controller likes create #likesコントローラーとcreateアクションを作成
```

```rb:likes_controller.rb
class LikesController < ApplicationController
  def create
    @like = Like.new(
    user_id: current_user.id,
    tweet_id: params[:tweet_id]
    )
    @like.save
    redirect_to("/")
    end
end

```


次にビューファイルを編集します。

```erb:views/tweets/show.html.erb
<div class="contents row">
    <div class="content_post" >
      <p><%= @tweet.text %></p>
       <p><%= image_tag @tweet.image.variant(resize: '500x500'), class: 'tweet-image' if @tweet.image.attached?%></p>
      <span class="name">
        <a href="/users/<%= @tweet.user.id %>">
        <span>投稿者</span><%= @tweet.user.nickname %>
      </a>
      <% if user_signed_in? && current_user.id == @tweet.user_id %>
      </span>
      <%= link_to '編集', edit_tweet_path(@tweet.id), method: :get %>
      <%= link_to '削除', "/tweets/#{@tweet.id}", method: :delete %>
       <% end %>
        <% if Like.find_by(user_id: current_user.id,tweet_id: @tweet.id)%>
       <%= link_to("いいね！済み","/tweets/#{@tweet.id}/likes/#{@like.id}",{method: "delete"}) %>
      <% else %>
      <%= link_to("いいね！","/tweets/#{@tweet.id}/likes",{method: "post"}) %>
      <% end %>
    </div>

    <div class="container">
    <% if user_signed_in? %>
      <%= form_with(model: [@tweet, @comment], local: true) do |form| %>
        <%= form.text_area :text, placeholder: "コメントする", rows: "2" %>
        <%= form.submit "コメント" %>
      <% end %>
    <% else %>
      <strong><p>※※※ コメントの投稿には新規登録/ログインが必要です ※※※</p></strong>
    <% end %>
     <div class="comments">
      <h4>＜コメント一覧＞</h4>
      <% @comments.each do |comment| %>
        <p>
          <strong><%= link_to comment.user.nickname, "/users/#{comment.user_id}" %>：</strong>
          <%= comment.text %>
        </p>
      <% end %>
    </div>
  </div>
</div>

```

##いいね取り消しボタンを作ろう
「いいね！」を取り消す機能を作るために、まずはlikesコントローラにdestroyアクションを作成しましょう。destroyアクション内では、受け取った@current_user.idとparams[:tweet_id]をもとに削除すべきLikeデータを取得し、destroyメソッドを用いて削除します。

##destroyアクションへのルーティングを設定

```rb:route.rb
Rails.application.routes.draw do
  get 'likes/create'
  devise_for :users
  root to: 'tweets#index'
  resources :tweets do
    resources :comments, only: :create
    resources :likes, only: [:create, :destroy]
    collection do
      get 'search'
    end
  end
  resources :users, only: :show
end
```

コントローラーにdestroyアクションを追加します。

```rb:likes_controller.rb
class LikesController < ApplicationController
  def create
    @like = Like.new(
    user_id: current_user.id,
    tweet_id: params[:tweet_id]
    )
    @like.save
    redirect_to("/tweets/#{params[:tweet_id]}")
    end

    def destroy
      @like = Like.find_by(user_id: current_user.id,tweet_id: params[:tweet_id])
      @like.destroy
      redirect_to("/tweets/#{params[:tweet_id]}")
      end
end
```

いいねボタンを♡アイコンにしてみましょう！

##Font Awesome
様々なアイコンをフォントとして利用できるようにしたものです。

「Font Awesome」を利用するには、<head>タグ内で読み込みをする必要があります。
application.html.erbに読み込み用の<link>タグを追加しましょう。

<span>に「fa fa-heart」というクラス名をつけることで、ハートアイコンを表示することができます。しかし、右の図のようにlink_toメソッド内にHTML要素を記述すると正しく表示することができません。

HTML要素に対してlink_toメソッドを使うには、少し異なる書き方をする必要があります。
右の図のように、<%= link_to(URL) do %>と<% end %>の間にHTML要素を書くことで、その部分をリンクにすることができます。

```erb:
ダメなパターン
<%= link_to("表示する文字列","URL") %> #文字列と判断されうまく表示されない

良いパターン
<%= link_to("URL") do　%>
<HTML要素の記述>
<% end %>

```

```erb:application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>Tsubuyaki</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
    <header class="header">
      <div class="header__bar row">
        <h1 class="grid-6"><a href="/">Tsubuyaki</a></h1>
       <div class="top_contents">
        <div class="user_nav grid-6">
       <% if user_signed_in? %>
          <div class="user_nav grid-6">
            <%= link_to "マイページ", "/users/#{current_user.id}", class: "post"  %>
            <%= link_to "ログアウト", destroy_user_session_path, method: :delete,class: "post"  %>
            <%= link_to "投稿する", new_tweet_path, class: "post" %>
          </div>
        <% else %>
          <div class="grid-6">
            <%= link_to "ログイン", new_user_session_path, class: "post" %>
            <%= link_to "新規登録", new_user_registration_path, class: "post" %>
          </div>
        <% end %>

        </div>
      </div>
    </header>
    <%= yield %>
    <footer>
      <p>
        Copyright Tsubuyaki 2021.
      </p>
    </footer>
  </body>
</html>

```


##いいねの数を数える
テーブルからデータの件数を取得するには、countメソッドを用います。
配列の要素数を取得するメソッドですが、テーブルのデータ数を取得することもできます。

それではコントローラーとビューファイルを編集していきましょう。

```rb:controllers/tweets_controller
class TweetsController < ApplicationController
  before_action :set_tweet, only: [:edit, :show]
  before_action :move_to_index, except: [:index, :show, :search]

  def index
    @tweets = Tweet.includes(:user).order("created_at DESC")
   
  end

  def new
    @tweet = Tweet.new
  end

  def create
    Tweet.create(tweet_params)
  end

  def destroy
    tweet = Tweet.find(params[:id])
    tweet.destroy
  end

  def edit
  end

  def update
    tweet = Tweet.find(params[:id])
    tweet.update(tweet_params)
  end

  def show
    @comment = Comment.new
    @comments = @tweet.comments.includes(:user)
    @like = Like.find_by(user_id: current_user.id, tweet_id: @tweet.id)
    @likes_count = Like.where(tweet_id: @tweet.id).count #カウントメソッド
  end

  def search
    @tweets = Tweet.search(params[:keyword])
  end

  private
  def tweet_params
    params.require(:tweet).permit(:image, :text).merge(user_id: current_user.id)
  end

  def set_tweet
    @tweet = Tweet.find(params[:id])
  end

  def move_to_index
    unless user_signed_in?
      redirect_to action: :index
    end
  end
end
```

ツイート詳細ページのビューも編集してハートと回数が表示されるようにします。

```erb:tweets/show.html.erb
<div class="contents row">
    <div class="content_post" >
      <p><%= @tweet.text %></p>
       <p><%= image_tag @tweet.image.variant(resize: '500x500'), class: 'tweet-image' if @tweet.image.attached?%></p>
      <span class="name">
        <a href="/users/<%= @tweet.user.id %>">
        <span>投稿者</span><%= @tweet.user.nickname %>
      </a>
      <% if user_signed_in? && current_user.id == @tweet.user_id %>
      </span>
      <%= link_to '編集', edit_tweet_path(@tweet.id), method: :get %>
      <%= link_to '削除', "/tweets/#{@tweet.id}", method: :delete %>
       <% end %>
        <% if Like.find_by(user_id: current_user.id,tweet_id: @tweet.id)%>
       <%= link_to("/tweets/#{@tweet.id}/likes/#{@like.id}",{method: "delete"})do %>
       <span class="fa fa-heart like-btn-unlike"></span>
       <% end %>
      <% else %>
      <%= link_to("/tweets/#{@tweet.id}/likes",{method: "post"})do %>
      <span class="fa fa-heart like-btn"></span>
      <% end %>
       <% end %>
       <%= @likes_count %>
    </div>

    <div class="container">
    <% if user_signed_in? %>
      <%= form_with(model: [@tweet, @comment], local: true) do |form| %>
        <%= form.text_area :text, placeholder: "コメントする", rows: "2" %>
        <%= form.submit "コメント" %>
      <% end %>
    <% else %>
      <strong><p>※※※ コメントの投稿には新規登録/ログインが必要です ※※※</p></strong>
    <% end %>
     <div class="comments">
      <h4>＜コメント一覧＞</h4>
      <% @comments.each do |comment| %>
        <p>
          <strong><%= link_to comment.user.nickname, "/users/#{comment.user_id}" %>：</strong>
          <%= comment.text %>
        </p>
      <% end %>
    </div>
  </div>
</div>

```

以上で完成です。
これでつぶやきアプリは完成となります。お疲れ様でした。