#はじめに
Railsで「qiita」のような記事をストックする機能を実装したので、その方法を備忘録としてまとめておきます。
(基本的にはいいね機能と同じやり方)
※また、以下に記載する方法は前提として**「Rails tutorial」**を最後まで終えた程で記載させていただきます。
#実装すること
・記事をストックするボタンを作成する。
・記事がどれくらいストックされているか表示する。
・ストックした投稿をストック一覧ページで確認できるようにする。
#Stockモデルを作成する
ストック機能を実装するにあたって、最初のステップとしてStockモデル
を作成します。
$ rails g model Stock
カラムは2つ作成します。
・post_id
カラム
・user_id
カラム
マイグレーションファイルは以下のように修正します。
class CreateStocks < ActiveRecord::Migration[6.0]
def change
create_table :stocks do |t|
t.references :user, foreign_key: true
t.references :post, foreign_key: true
t.timestamps
end
add_index :stocks, [:user_id, :post_id], unique: true
end
end
$ rails db:migrate
2つのカラムは、それぞれ外部キーとして追加しておきます。
このテーブルは中間テーブルとして活用し、誰がどの投稿をストックしたかという情報を格納しておきます。
また、user_id
カラムとpost_id
カラムの組み合わせが一意になるようにインデックスを設定しておきます。
#アソシエーションを設定する
以下のようにアソシエーションを設定します。
stock.rb
にはアソシエーションのついでにバリデーションも追加しておきます。
##user.rb
has_many :stocks, dependent: :destroy
##post.rb
has_many :stocks, dependent: :destroy
##stock.rb
belongs_to :user
belongs_to :post
validates :user_id, presence: true
validates :post_id, presence: true
#stockコントローラを作成する
次にstockコントローラ
を作成します。
$ rails g controller Stocks
#コントローラに処理を加える
##stocks_controller.rb
stockコントローラ
を作成したら、今回の実装に必要なアクションを定義しておきます。
class StocksController < ApplicationController
def create
@stock = current_user.stocks.create(post_id: params[:post_id])
redirect_back(fallback_location: root_path)
end
def destroy
@stock = Stock.find_by(
post_id: params[:post_id],
user_id: current_user.id
)
@stock.destroy
redirect_back(fallback_location: root_path)
end
def index
@stocks = Stock.where(user_id: current_user.id)
end
end
##posts_controller.rb
次にpostコントローラ
のshowアクションの部分に変数を追加します。
post/showページにストックボタンを表示する為です。
def show
@post = Post.find_by(id: params[:id])
@stock = Stock.find_by(
user_id: current_user.id,
post_id: @post.id
)
end
#ルーティングを設定する
次に必要なルーティングを追加していきます。
##routes.rb
resources :stocks, only:[:create, :destroy, :index]
今回はストックする機能**(create)とストックを解除する機能(destroy)の他にストックした記事を表示する為の「index」**も追加しておきます。
#ストックしているかどうかの確認の処理と加える
ユーザーが記事に対して、すでにいストックをしているのかどうかを確認することができるようにstock?
メソッドを定義しておきます。
##user.rb
#ユーザーがすでにストックしているか確認する
def stock?(post)
self.stocks.exists?(post_id: post.id)
end
#Viewを追加&変更する
ストックボタンを実装する為に、まずはパーシャルを3つ作成していきます。
##shared/_stock.html.erb
<%= form_with(url:stocks_path, local: true) do |f| %>
<div><%= hidden_field_tag :post_id, @post.id %></div>
<%= f.submit "ストック", class:"btn-sm" %>
<% end %>
##shared/_unstock.html.erb
<%= form_with(url: stock_path(@stock), html: {method: :delete}, local: true) do |f| %>
<div><%= hidden_field_tag :post_id, @post.id %></div>
<%= f.submit "ストックをやめる", class:"btn-sm" %>
<% end %>
##shared/_stock_form.html.erb
<% if current_user.stock?(@post) %>
<%= render "shared/unstock" %>
<% else %>
<%= render "shared/stock" %>
<% end %>
<%= @post.stocks.count %>
##posts/show
ボタンを追加したいところに以下パーシャルを追加します。
<%= render "shared/stock_form" %>
##stocks/index.html.erb
indek
ページを新しく追加し、ストックした記事を表示させます。
<h1>ストック一覧</h1>
<h2>あなたがストックしたポートフォリオの一覧です。</h2>
<% @stocks.each do |stock| %>
<%= link_to stock.post.name, post_path(stock.post) %>
<% end %>
#完成画
#おわり
以上で終了です。
機能の実装方法を記述しているので、デザインは全く気にしていません。
デザインはお好みで付け足してみてください。
#ソースコードはこちら
ポートフォリオ作成中のものですが。以下にあります。
https://github.com/iittaa/Sharing_Portfolio