どうもこんにちは、
今回は、僕がとても手こずった機能である
いいね機能
について紹介します👍
いろんな記事を参考に進めたのですが、
なかなかうまく行かなかったので、記録として残しておき、
後世に語り継ぎたいと思います。(大げさ)
では早速やっていきましょう!
この記事は以下の情報を参考にして執筆しました。
まず
% rails g model Favorite user_id:integer book_id:integer
マイグレーションファイルに記述します
class CreateFavorites < ActiveRecord::Migration[6.0]
def change
create_table :favorites do |t|
t.integer :user_id
t.integer :book_id
t.timestamps
t.index [:user_id, :book_id], unique: true これで一意性をつけている
end
end
end
t.indexについてはstackoverflowに詳しく話しているのがあります
そして忘れずに
$ rails db:migrate
お次はこれらを追加
class Favorite < ApplicationRecord
belongs_to :user
belongs_to :book
end
belongs_to :user
has_many :users, through: :favorites throughでbookとuserをつないでます
has_many :favorites
*1
def favorited_by?(user)
favorites.where(user_id: user.id).exists?
end
has_many :books
has_many :favorites
has_many :favorite_books, through: :favorites, source: :book 同じく
そして、
*1に関しては、この後使うので少々お待ち下さい
今はメソッドを生成しているとだけご理解ください。
次にビューとコントローラーを作っていきます
% rails generate controller favorites create destroy
最後にcreate destroyと付け足すことで
この二つのビューだけ作ってくれます
<div class="favorite-button">
<% if user_signed_in? %>
<% if book.favorited_by?(current_user) %>
<%=link_to "💔 #{book.favorites.count}",book_favorites_path(book.id), method: :delete, class: 'btn btn-default', remote: true %>
<% else %>
<%= link_to "💖 #{book.favorites.count}", book_favorites_path(book.id), method: :post, class: 'btn btn-default', remote: true %>
<% end %>
<% else %>
<button><span>お気に入り数: </span><%= book.favorites.count %>
<% end %>
</div>
_favoriteとわざわざ切り出してるのは、可読性を上げるため?
とAjax化のためだそうです
remote tureをつけ忘れるとAjax化できなくなるそうです
remote tureをつけると
リクエストがhtml形式ではなくjs形式になる!
とこの記事では書かれています
remote true参考記事
$('#favorites_buttons_<%= @book.id %>').html("<%= j(render partial: 'favorites/favorite', locals: {book: @book}) %>");
$('#favorites_buttons_<%= @book.id %>').html("<%= j(render partial: 'favorites/favorite', locals: {book: @book}) %>");
そしていいねボタンを作りたいところにこれ!!!!!
<div class="like">
<%# いいね %>
<div id="favorites_buttons_<%= @book.id %>">
<%= render partial: 'favorites/favorite', locals: { book: @book } %>
</div>
<%# いいね %>
render の後は呼び出したいファルダ名(ディレクトリ名)を指定
id はボタンを押したとき反応してくれるところなので忘れずに記入記入
class FavoritesController < ApplicationController
def create
@book = Book.find(params[:book_id])
@favorite = current_user.favorites.build(book_id: params[:book_id])
@favorite.save
end
def destroy
@book = Book.find(params[:book_id])
@favorite = Favorite.find_by(book_id: params[:book_id], user_id: current_user.id)
@favorite.destroy
end
end
コントローラーはこんな感じ。
僕、前ここにriderect_toをつけていたせいで
思うように動かなかったんですよね。。
本来Ajax化のために
favorites/create.js.erb
に飛んで処理が実行されなきゃいけないんですけど
redirect_toが邪魔してました、、
こんな感じでできあがりです!!
いかがだったでしょうか。
これで実装できなったら、バージョンなどを確認して見てください。
バージョン違うだけで結構変わるらしいので!
{僕もそれでハマりました。)
ちなみに今回はバージョンRuby 6.0.0です