こんにちは、今回はお気に入り機能の作り方について書いていきます。
ちなみに下記の2つの記事を参考にさせていただきました。
http://labyrinth-of-wisdom.hatenadiary.com/entry/2016/03/03/085059
https://qiita.com/wtb114/items/39367a39bd6a65701db7
さて、ではまずざっと流れを書いていきます。
1.Favoriteモデルの作成
2.モデルのアソシエーション、favoriteのDB作成
3.Routing,Controller,Viewの設定
では、まず1の前にお気に入り機能について簡単に説明していきましょう。
お気に入りは、Userがある投稿につけるものでありますが、お気に入りにおいてはUserとPostは多対多の関係にあると言えます。
Userは多くのお気に入りPostを持っています
Postを多くのお気に入り(By User)を持っています。
ということで、「User1の人だからお気に入りはこのPostでしょ」も「Post1だから、この人のお気に入りでしょ」みたいな断定はできないんですね。要するにもれなく、片方からもう片方にアクセスすることはできないってことです。
ということで、中間テーブルを作るわけです。正直説明下手ですね、すいません。
関係を結んだ後は、お互いのテーブルから他方にアクセスできるようになります。
1.Favoriteモデルの作成
これはおなじみですね。
rails g model Favorite
2.モデルのアソシエーション
3つのモデルについて書いていきます。
class Favorite < ApplicationRecord
belongs_to :user
belongs_to :post
end
これはuserとpostに1対多で属するので、2つかきます。
class User < ApplicationRecord
has_many :favorites
has_many :posts, through: :favorites
end
Userモデル。favoriteモデルはhas_manyですね。
postは、favoriteモデルを経由して取ってくるので、has_many ,thoroughですね。
イメージとしては、Userモデルのidが2番目の人のお気に入りをしているPostを取ってくる場合
Userモデル (id=2)
=> Favoriteモデル (user_id=2のものを探索)
=> Favoriteモデル (探索したものの、post_idを発見)
=> Postモデル(post_idからPostモデル内のidに変換。たどり着く)
みたいなイメージです。
もしくは、中間テーブルでPostとUserががっちゃんこみたいなイメージでもいいかもしれません。
class Post < ApplicationRecord
has_many :favorites
has_many :users, through: :favorites
end
これは一緒です。
さてこのタイミングでfavoriteのDBを作成しましょう。
class CreateFavorites < ActiveRecord::Migration[5.1]
def change
create_table :favorites do |t|
t.references :user, null:false
t.references :post, null:false
t.timestamps
end
end
end
t.references :user という項目を作りました。ちなみにuser_idでもOKです。自動でkeyだと読み取ってくれます。ちなみに、add_index :favorites, :user_id とするとエラーが起きました。rails4以降は、refrencesとすると、自動でindexをつけてくれるみたいですね。便利。
これでrails db:migrate!
これで、アソシエーションと、モデルは終了です。
あとは、Favoriteモデルに追加する方法、実際に片側のモデルからもう一方のモデルにデータをとるってことをやりましょう。
Controller
class FavoritesController < ApplicationController
def create
user=current_user
post=Post.find(params[:post_id])
if Favorite.create(user_id: user.id,post_id:post.id)
redirect_to post
else
redirect_to root_url
end
end
def destroy
user=current_user
post=Post.find(params[:post_id])
if favorite=Favorite.find_by(user_id: user.id,post_id:post.id)
favorite.delete
redirect_to users_path(current_user)
else
redirect_to root_url
end
user_idとpost_idがわかればテーブルを作れるのでこちらでお願いします。
###Routing
resources :posts do
post 'add' => 'favorites#create'
delete '/add' => 'favorites#destroy'
end
postはparams[post_id]から取っているので、postのidがどうしても必要です。ということで、ネストしてurlを作成しました。イメージとしては、doとendに囲まれた中では、普通のroutingの形式でいいみたいです。ルートアドレスが、/posts/:idになったイメージです。resourcesにネストしてるので。
最後にformですね。これは、/posts/:id/addにpostかdeleteを送ればオッケーなので下記になります。
<% if !Favorite.exists?(user_id:current_user.id,post_id:post.id) %>
<%= link_to "お気に入り",post_add_path(post),method: :post %>
<% else %>
<%= link_to "お気に入り解除",post_add_path(post),method: :delete %>
これはそんな難しくないはずです。exists?メソッドを使って切り替えもしました。
以上です。
ありがとうございました。初心者なので、意見あればガシガシお願いします!!a