FreeCamp

いいね機能の作成

TwitterやInstagramなどのSNSには「いいね」という機能があります。
この機能を実際にRailsで実装してみます。

見出し

  1. 「いいね」とは
  2. ユーザー認証機能の実装
  3. 投稿機能の実装
  4. いいね機能の実装
  5. 完成コード

1. 「いいね」とは

いいねとは何でしょうか?
アプリケーションにはユーザーと投稿が存在していることを前提とします。
具体的にはユーザーテーブルと投稿のテーブルが存在していることとなります。
ユーザーが3人いてそれぞれIDが1, 2, 3、投稿も三つありIDが1, 2, 3とします。
いいねとはユーザーと投稿のIDがセットになっている状態のことを指します。
例えば、ユーザーIDが1, 投稿IDが1がセットになっていればID1のユーザーが投稿1をいいねしている状態となります。
「いいね」は概念でしかないため、他のアプリケーションでは「一時保存」や「あとで見る」、「キープ」など言い換えている場合があります。

こちらの画像ではユーザー1が投稿1, 2、ユーザー3が投稿1をいいねしているという状態を表しています。

2. ユーザー認証機能の作成

ユーザーがいなければいいねはできませんので、ユーザー認証機能を作成していきます。
まずは、アプリケーションの基盤を作成し、その後ユーザー認証機能を作成します。
ユーザー認証機能は下記リンクを参考にして作成しても良いです。

$ rails new sample_app
$ cd sample_app
...追加
gem 'devise'
$ bundle
$ rails g devise:install
$ rails g devise User
$ rails db:migrate

トップページを作成します。

$ rails g controller home top
...編集
get 'home/top'
↓
root 'home#top'
...編集
<body>
  <% if user_signed_in? %>
    <%= link_to 'ログアウト', destroy_user_session_path, method: :delete %>
  <% else %>
    <%= link_to 'ログイン', new_user_session_path %>
    <%= link_to '新規登録', new_user_registration_path %>
  <% end %>
  <%= yield %>
</body>

これで新規登録・ログイン・ログアウトができるようになりました。
http://localhost:3000にアクセスして試してみましょう。

3. 投稿機能の実装

次に投稿機能を作成します。
こちらを一つ一つ説明すると長くなるため、下記記事を参考にして進めていきます。

Scaffoldを導入していきます。

$ rails g scaffold post title:string user_id:integer
$ rails db:migrate
...追加
<%= link_to '投稿一覧', posts_path %>

ログインしているユーザーしか投稿関連を行えないように、
posts_controller.rbの3行目あたりに以下を追加します。

...追加
before_action :authenticate_user!

投稿とユーザーを紐づけていきます。

...追加
belongs_to :user
...追加
has_many :posts

Scaffoldで作成するとuser_idのフォームが作成されてしまうため、
_form.html.erbの下記を削除します。

<div class="field">
  <%= form.label :user_id %>
  <%= form.number_field :user_id %>
</div>

また、ストロングパラメータからもuser_idを削除します。

...編集
params.require(:post).permit(:title)

投稿作成時にログインしているユーザーのidを格納する様にします。

...編集
def create
    @post = Post.new(post_params)
    @post.user_id = current_user.id

ここまでで、ユーザー認証機能と投稿機能を作成することはできました。

4. いいね機能の実装

まずはユーザーIDと投稿IDを格納するためのモデルを作成します。

$ rails g model Favorite user_id:integer post_id:integer
$ rails db:migrate

userモデル, postモデル, favoriteモデルそれぞれに関連付けをしていきます。

...追加
has_many :favorites
...追加
has_many :favorites
...追加
belongs_to :user
belongs_to :post

また、ユーザーがいいねしている投稿を取得できるように
モデルでthroughオプションを利用した関連付けを行います。

...追加
has_many :favorite_posts, through: :favorites

そして、いいねしているかを投稿の右側に表示させます。
まずはいいねしているかどうかを確かめる関数をuser.rbに記載します。

...追加
def favorited_by?(post_id)
  favorites.where(post_id: post_id).exists?
end
...編集
<td><%= post.title %></td>
<% if current_user.favorited_by?(post.id) %>
  <td>いいね外す</td>
<% else %>
  <td>いいねする</td>
<% end %>
<td><%= link_to 'Show', post %></td>
<td><%= link_to 'Edit', edit_post_path(post) %></td>
<td><%= link_to 'Destroy', post, method: :delete, data: { confirm: 'Are you sure?' } %></td>

次に、いいねを実際したり外したりできるようにします。

$ rails g controller favorites
...追加
def create
  Favorite.create(user_id: current_user.id, post_id: params[:id])
  redirect_to posts_path
end

def destroy
  Favorite.find_by(user_id: current_user.id, post_id: params[:id]).destroy
  redirect_to posts_path
end

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

...追加
post 'favorite/:id' => 'favorites#create', as: 'create_favorite'
delete 'favorite/:id' => 'favorites#destroy', as: 'destroy_favorite'

ビューを編集します。

<td><%= post.title %></td>
<% if current_user.favorited_by?(post.id) %>
  <td><%= link_to 'いいね外す', destroy_favorite_path(post), method: :DELETE %></td>
<% else %>
  <td><%= link_to 'いいねする', create_favorite_path(post), method: :POST %></td>
<% end %>
<td><%= link_to 'Show', post %></td>
<td><%= link_to 'Edit', edit_post_path(post) %></td>
<td><%= link_to 'Destroy', post, method: :delete, data: { confirm: 'Are you sure?' } %></td>

ここまででいいね機能を作成することができました。
次回はいいね数を取得できるようにしていきます。

5. 完成コード

https://github.com/ssshhhooota/rails_favorite