1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

非公開のリソースにURLでアクセスされたらどうする?(例えば非公開記事とか)

Posted at

やりたいこと

投稿者が記事を投稿します。
投稿した記事は、公開/非公開(active/inactive)を設定できます。
読者側のページでは、公開記事を一覧で表示して(index)、各記事にアクセスできるようにします(show)。

読者側ページでは非公開記事は表示せず、遷移する動線を提示しないのは当然ですが、これをしただけでは、記事のURLからアクセスされたら非公開記事も見られてしまいます。

どうすれば良いでしょうか?

環境
ruby 2.7.2
Rails 6.1.3.1

投稿データを扱うこんなモデルがあったとします:point_down:
公開/非公開を制御するために、statusというカラムを持たせて、enumで定義します。

post.rb
# == Schema Information
#
# Table name: posts
#
#  id               :bigint           not null, primary key
#  title            :text             not null
#  body             :text             not null
#  status           :integer          not null
#  created_at       :datetime         not null
#  updated_at       :datetime         not null

enum status:       { active: 10, inactive: 20 }

選択肢1:リダイレクトする

リダイレクトすれば確かに非公開記事にはアクセスできなくなりますが、それが本当に存在しない出鱈目なURLの記事にアクセスした時と違う挙動(例外とか)になると、そのURLの先にリソースがあるということは暗示してしまいます。
Webサイトの考え方にもよるかもしれませんが、多くの場合は、本当に存在しないURLと同じ挙動になるように、例外を出してあげた方が良さそうです。

一応リダイレクトを是として実装するなら、こんな感じでしょうか。

class Reader::PostsController < Reader::ApplicationController
  before_action :set_post, only: %i[show]

  def show
    redirect_to reader_posts_path if @post.status_inactive?
  end

  private

  def set_post
    @post = Post.find_by(id: params[:id])
  end
end

選択肢2:404を返す

404とは、HTTPステータスコードの一種で、「サーバーには到達できたけど、あなたのリクエストしたもの(投稿)は無かったよ」というメッセージです。つまり、全く存在しない記事のURLを入力された時と同様、例外にしてあげます。
実装は驚くほどシンプルに実現できます。

post_controller.rb
class Reader::PostsController < Reader::ApplicationController
  before_action :set_post, only: %i[show]

  def show; end

  private

  def set_post
    @post = Post.active.find_by!(id: params[:id])
  end
end
.active
モデルのenumで定義している`active`をこんな感じで使えるんですね!これでpostsテーブルの中で、find_byする前にactiveのものだけに絞り、非公開記事を除くことができます。 

find_by!
エクスクラメーションマークのないfind_byとは違う挙動をします。指定されたレコードが見つからなかった時、find_by!はfind_byはActiveRecord::RecordNotFound例外を発生させ、find_byはnilを返します。find_by!は見つからなかったらその時点で「Couldn't find Post with...」というエラーを出してくれます。find_byはビューをレンダーするところまで到達して、 @postを参照し、ここで`undefined method 'title' for nil:NilClass`というエラーになります。
開発者ツールのNetworkでも確認できます。

find_by!
couldnfiind404.png

find_by
undefinedmethod500.png
find_byの時は500エラーなのか:astonished:

最後に

何かご指摘などあれば、ビシビシお願いします。

毎度毎度ですが、会社の先輩 @Y_uuu さんに大感謝です。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?