LoginSignup
14
9

More than 5 years have passed since last update.

Punditのrspecをカイゼンしてみた

Last updated at Posted at 2015-06-24

Railsの権限管理にPunditを使うようになったのですが、標準のmatcherだとオブジェクトの操作に対して挙動を記述していきます。そうすると、あるユーザがどのような権限をもっているかがわかりにくい気がしました。

まず、Punditの標準でついてくるmatcherだとREADMEにあるようにこのような記述をします。

spec/policies/post_spec.rb
describe PostPolicy do
  subject { described_class }

  permissions :update? do
    it "denies access if post is published" do
      expect(subject).not_to permit(User.new(:admin => false), Post.new(:published => true))
    end

    it "grants access if post is published and user is an admin" do
      expect(subject).to permit(User.new(:admin => true), Post.new(:published => true))
    end

    it "grants access if post is unpublished" do
      expect(subject).to permit(User.new(:admin => false), Post.new(:published => false))
    end
  end
end

アプリケーションによっては、ユーザの権限がどのような操作ができるのかという書き方をしたほうがわかりやすい場合があるのではないでしょうか。そのような場合は、ここで紹介しているやり方が参考になりました。

spec/support/pundit_mathcer.rbを作成します。

spec/support/pundit_mathcer.rb
RSpec::Matchers.define :authorize do |action|
  match do |policy|
    policy.public_send("#{action}?")
  end

  failure_message_for_should do |policy|
    "#{policy.class} does not permit #{action} on #{policy.record} for #{policy.user.inspect}."
  end

  failure_message_for_should_not do |policy|
    "#{policy.class} does not forbid #{action} on #{policy.record} for #{policy.user.inspect}."
  end
end

spec/rails_helper.rbに下記を追加します。

spec/rails_helper.rb
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}

そうすると、このような記述でPolicyのspecが書けます。

spec/policies/article_spec.rb
require 'rails_helper'

describe ArticlePolicy do
  subject { ArticlePolicy.new(user, article) }

  let(:article) { FactoryGirl.create(:article) }

  context "for a visitor" do
    let(:user) { nil }

    it { should     authorize(:show)    }

    it { should_not authorize(:create)  }
    it { should_not authorize(:new)     }
    it { should_not authorize(:update)  }
    it { should_not authorize(:edit)    }
    it { should_not authorize(:destroy) }
  end

  context "for a user" do
    let(:user) { FactoryGirl.create(:user) }

    it { should authorize(:show)    }
    it { should authorize(:create)  }
    it { should authorize(:new)     }
    it { should authorize(:update)  }
    it { should authorize(:edit)    }
    it { should authorize(:destroy) }
  end
end
14
9
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
14
9