Ruby on Railsで下書き機能を実装するために場合分けしてみた

はじめまして。
Ruby on Rails勉強中のfkdollyと申します。
現在のところ独学での勉強につき、間違っている箇所があればご指摘いただければ幸いです。


現在Railsでアプリを開発中でして、その中で投稿に下書き機能をつけたいと思い、下記の記事を始めとして色々調べてみました。
[Railsで下書き機能を独自に実装した時の過程をまとめてみた](https://qiita.com/h5y1m141@github/items/cccc47643910cbbb1577 "Railsで下書き機能を独自に実装した時の過程をまとめてみた")


ですが、モデルをもう一つ作るとより頭がこんがらがりそうだったので(笑)、Postモデルの中で何とかする方法を考えました。


まず、搭載する下書き機能について以下のようなものを考えました。

- 投稿一覧画面では投稿した本人がログインしている時のみ下書き一覧を表示する。他のユーザーまたは未ログインユーザーがアクセスしても公開済みの投稿のみ表示。
- 投稿詳細画面も同様に下書きを投稿した本人がログインしている時のみアクセス可能。その他のユーザーはアクセス不可。公開済み記事には全ユーザーがアクセス可能。


そこでPostテーブルにStatusカラムを追加し、Draft/Publishのどちらかによって下書き/公開済みを切り替えることとしました。
また、アクセスしたユーザーが本人かどうかについてはセッションで判断することとしました。

```ruby:users_controller.rb
def login
    @user = User.find_by!(name: params[:name], password: params[:password])
    if @user
      session[:user_id] = @user.id
      flash[:notice] = "ログインしました"
        redirect_to("/#{@user.id}")
    else
      redirect_to("/login")
    end
  end
```

ユーザー本人か否か/Draft記事があるか否か/Publish記事があるか否かの2×2×2=8通りなので条件分岐していきます。Userモデルのshowアクションでそのユーザーの投稿一覧を表示しており、下記のように書きました。

```ruby:show.html.erb
<% posts_draft = Post.where(user_id: @user.id, status: "draft") %>
<% posts_publish = Post.where(user_id: @user.id, status: "publish") %>

# ユーザー本人かつ下書きも公開済み記事もある場合
<% if session[:user_id] == @user.id && posts_draft.present? && posts_publish.present? %>
<div class="post_status">下書きが残っています。投稿を公開しよう！</div>
<% posts_draft.each do |post| %>
	# Draft一覧
<% end %>
<div class="post_status">公開済み</div>
<% posts_publish.each do |post| %>
	# Publish一覧
<% end %>

# ユーザー本人かつ下書きのみある場合
<% elsif session[:user_id] == @user.id && posts_draft.present? && posts_publish.empty? %>
<div class="post_status">下書きが残っています。投稿を公開しよう！</div>
<% posts_draft.each do |post| %>
	# Draft一覧
<% end %>

# ユーザー本人かつ公開済み記事のみある場合
<% elsif session[:user_id] == @user.id && posts_draft.empty? && posts_publish.present? %>
<div class="post_status">公開済み</div>
<% posts_publish.each do |post| %>
	# Publish一覧
<% end %>

# ユーザー本人かつ下書きも公開済み記事も無い場合
<% elsif session[:user_id] == @user.id && posts_draft.empty? && posts_publish.empty? %>
<div class="post_not_yet">投稿はありません。投稿しよう！</div>
<% end %>

# その他のユーザーかつ下書きも公開済み記事もある場合、または公開済み記事のみある場合
<% elsif (session[:user_id] != @user.id && posts_draft.present? && posts_publish.present?) || (session[:user_id] != @user.id && posts_draft.empty? && posts_publish.present?) %>
<% posts_publish.each do |post| %>
	# Publish一覧
<% end %>

# その他のユーザーかつ下書きのみある場合、または下書きも公開済み記事も無い場合
<% else %>
	<div class="post_not_yet">投稿はありません。</div>
<% end %>
<% end %>
```

下2つは表示する内容が同じなのでまとめた結果6通りの場合分けになりました。
実際のコードではユーザー本人によるアクセスの場合は編集ボタンと削除ボタンも表示しています。


また、投稿詳細画面はPostモデルのshowアクションで表示しています。上記のコードで画面上は表示されませんが、URLを直接入力するとアクセスできてしまうので、コントローラで下記のようにしました。

```ruby:post_controller.rb
def show
    @post = Post.find_by(id: params[:id])
    @user = User.find_by(id: @post.user_id)
    if session[:user_id] == nil && @post.status == "draft"
      redirect_to("/login")
    elsif session[:user_id] != @user.id && @post.status == "draft"
      redirect_to("/#{@current_user.id}")
    end
end
```

以上のような形で実装してみました。今のところは問題ないハズです。
が、要素がこれ以上増えるとこうした場合分けを使うのは現実的では無いと思うので別の方法も勉強してみたいと思います。やっぱりもっとシンプルにできる気がする...
こういう方法もあるよ！というのがあればぜひ教えてください！