2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Posted at

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

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カラムを作成します。

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

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

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

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アクションを作成
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

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

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アクションへのルーティングを設定

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アクションを追加します。

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」を利用するには、

タグ内で読み込みをする必要があります。
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 %>

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メソッドを用います。
配列の要素数を取得するメソッドですが、テーブルのデータ数を取得することもできます。

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

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

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

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>

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

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?