はじめに
制作しているポートフォリオに記事の公開・非公開機能を追加したので、実装手順を紹介します。
記事を投稿したけど、一旦非公開にしたい時があると思うので、実装してみました。
前提
- kaminariのgemの機能を使用し、非公開記事一覧取得してます
- deviseのgemの機能を使用し、他ユーザーを非公開記事からリダイレクトさせてます
バージョン情報
- Ruby 2.6.3
- Rails 6.0.2.1
実装した手順
postsテーブルにstatus用のカラムを追加
$ rails g migration Add_status_To_posts status:integur
db/migrate/20201111213454_add_status_to_posts.rb
class AddStatusToPosts < ActiveRecord::Migration[6.0]
def change
add_column :posts, :status, :integer, null: false, default: 0
end
end
モデルを定義
app/models/post.rb
class Post < ApplicationRecord
#・・・省略
enum status: { public: 0, private: 1 }, _prefix: true
#・・・省略
end
上記のように_prefix: true
を記述してない状態でブラウザを開いたら、下記のエラーが出た。
エラー文を確認すると、public
というメソッドが重複しているとのこと。
重複してエラーが出ていなければ_prefix: true
を記述しなくてもOK。
log/development.log
ArgumentError (You tried to define an enum named "status" on the model "Post", but this will generate a class method "public", which is already defined by Active Record.):
app/models/post.rb:19:in `<class:Post>'
app/models/post.rb:1:in `<main>'
app/controllers/posts_controller.rb:85:in `set_post'
Started GET "/posts/3" for 127.0.0.1 at 2020-11-12 06:52:36 +0900
Cannot render console from 172.22.0.1! Allowed networks: 127.0.0.0/127.255.255.255, ::1
[1m[35m (1.2ms)[0m [1m[35mSET NAMES utf8mb4, @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'), @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483[0m
Processing by PostsController#show as HTML
Parameters: {"id"=>"3"}
Completed 500 Internal Server Error in 27ms (ActiveRecord: 0.0ms | Allocations: 5566)
投稿編集ページで投稿ステータスを選択できるようにする
app/views/posts/_form.html.erb
<%= form_with(model: post, local: true) do |form| %>
<!--・・・省略・・・-->
<%= form.label(:public, for: nil, class:'post-status__label') do %>
<%= form.radio_button :status, :public %>
<%= I18n.t('activerecord.attributes.post.statuses.public') %>
<% end %>
<%= form.label(:private, for: nil, class:'post-status__label') do %>
<%= form.radio_button :status, :private %>
<%= I18n.t('activerecord.attributes.post.statuses.private') %>
<% end %>
<!--・・・省略・・・-->
<% end %>
公開・非公開を選択するUIは下記のようにしました。
この記事でははその実装手順はメイントピックではないので、割愛。
しかし、この実装に時間かかってしまった。
選択した投稿ステータスを保存できるようにする
app/controllers/posts_controller.rb
class PostsController < ApplicationController
# ・・・省略
def create
@post = Post.new(post_params)
@post.user_id = current_user.id
respond_to do |format|
if @post.save
format.html { redirect_to @post, notice: '新規投稿を行いました。' }
format.json { render :show, status: :created, location: @post }
else
format.html { render :new }
format.json { render json: @post.errors, status: :unprocessable_entity }
end
end
end
# ・・・省略
private
# ・・・省略
def post_params
params.require(:post).permit(
:title,
:content,
:image,
:status, # <= 追加:statusカラム
{:cat_ids => []}
)
end
# ・・・省略
end
非公開記事一覧、詳細ページは、他のユーザーにアクセス時にはリダイレクトさせる
app/controllers/posts_controller.rb
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
# GET /posts/1
# GET /posts/1.json
def show
if @post.status_private? && @post.user != current_user
respond_to do |format|
format.html { redirect_to posts_path, notice: 'このページにはアクセスできません' }
end
end
# ・・・省略
end
# ・・・省略
private
def set_post
@post = Post.find(params[:id])
end
# ・・・省略
end
記事一覧の取得方法
# 公開記事
$ Post.status_public.order(created_at: :desc).page(params[:page])
# 非公開記事
$ Post.status_private.order(created_at: :desc).page(params[:page])
# ランキング(Likeのトップ3)
$ Post.status_public.joins(:likes).group(:post_id).order('count(likes.post_id) desc').limit(3)
所要時間
作業内容 | 所要時間 |
---|---|
見積 | 0.75H |
実装・検証:新規投稿 | 7H |
実装・検証:ユーザー詳細ページ | 2.25H |
実装・検証:投稿詳細ページ(localhost/posts/:id) | 1H |
実装・検証:記事一覧・詳細ページ(Like Ranking) | 0.5H |
実装・検証:記事一覧(localhost/posts) | 0.125H |
実装・検証:TOP(localhost) | 0.125H |
合計 | 12H |
投稿編集ページを作るのに7Hかかってしまったので反省だが、なんとか作れたので良かったかな
さいごに
記事の公開・非公開機能追加の際にこの記事が参考になれば幸いです。
参考
【Rails】enumチュートリアル
Rails5 から enum 使う時は_prefix(接頭辞)_suffix(接尾辞)を使おう