スコープを使ってアクセスする

元記事はこちら

翻訳

オブジェクトのオーナーとcurrent_userを比較することで、アクセス権をチェックしたいとおもったら、そんな冗長でイケてない書き方はせずに、スコープをつかてアクセスしましょう。

Bad Smell

class PostsController < ApplicationController
  def edit
    @post = Post.find(params[:id])
    if @post.user != current_user
      flash[:warning] = 'Access denied'
      redirect_to posts_url
    end
  end
end

上記の例では、postのuserをcurrent_userと比較して、一致しなかった場合に、postの編集を許可しないようにしている。 しかし、このやり方は、edit,update,destroyなどを実行できるかチェックするには冗長すぎる。スコープを使ってリファクタリングしよう。

Refactor

class PostsController < ApplicationController
  def edit
    # raise RecordNotFound exception (404 error) if not found
    @post = current_user.posts.find(params[:id])
  end
end

こうすることで、current_user.postsにだけ紐づくpost、言い換えるとcurrent_userに紐づくことが保証されたpostを検索することができた。 紐付いたpostが存在しない場合、404エラーが返却される。 current_userとオーナーを比較する必要は全くなく、スコープアクセスを使うだけでアクセス権のチェックをより単純に書くことができる。

感想

404が返るってところは、厳密に言うとActiveRecord::RecordNotFoundがraiseされて、rescue_fromを書いていれば、ActionController::Rescueがひろう仕組みらしい。