最後にいいね機能を追加しましょう。
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カラムを作成します。
モデル間のアソシエーションを組みます。
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
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
class Like < ApplicationRecord
belongs_to :user
belongs_to :tweet
end
ルーティングを設定します。
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アクションを作成
class LikesController < ApplicationController
def create
@like = Like.new(
user_id: current_user.id,
tweet_id: params[:tweet_id]
)
@like.save
redirect_to("/")
end
end
次にビューファイルを編集します。
<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アクションへのルーティングを設定
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アクションを追加します。
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」を利用するには、
タグ内で読み込みをする必要があります。application.html.erbに読み込み用のタグを追加しましょう。
に「fa fa-heart」というクラス名をつけることで、ハートアイコンを表示することができます。しかし、右の図のようにlink_toメソッド内にHTML要素を記述すると正しく表示することができません。
HTML要素に対してlink_toメソッドを使うには、少し異なる書き方をする必要があります。
右の図のように、<%= link_to(URL) do %>と<% end %>の間にHTML要素を書くことで、その部分をリンクにすることができます。
ダメなパターン
<%= link_to("表示する文字列","URL") %> #文字列と判断されうまく表示されない
良いパターン
<%= link_to("URL") do %>
<HTML要素の記述>
<% end %>
<!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メソッドを用います。
配列の要素数を取得するメソッドですが、テーブルのデータ数を取得することもできます。
それではコントローラーとビューファイルを編集していきましょう。
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
ツイート詳細ページのビューも編集してハートと回数が表示されるようにします。
<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>
以上で完成です。
これでつぶやきアプリは完成となります。お疲れ様でした。