Merge branch 'atomaka/feature/authorization' into 'master'

Add authorization via Pundit

Also includes some a refactor to null object pattern for guest users.

See merge request !24
This commit is contained in:
Andrew Tomaka 2015-12-23 20:47:12 +00:00
commit 1f9788309b
31 changed files with 678 additions and 231 deletions

View file

@ -4,4 +4,5 @@ test:
- apt-get install -y nodejs libqtwebkit-dev qt4-qmake sqlite3 libsqlite3-dev - apt-get install -y nodejs libqtwebkit-dev qt4-qmake sqlite3 libsqlite3-dev
- bundle install --path /cache - bundle install --path /cache
- bundle exec rake db:create RAILS_ENV=test - bundle exec rake db:create RAILS_ENV=test
- bundle exec rake db:test:prepare
- bundle exec rspec - bundle exec rspec

10
Gemfile
View file

@ -1,13 +1,5 @@
source 'https://rubygems.org' source 'https://rubygems.org'
def darwin_only(require_as)
RbConfig::CONFIG['host_os'] =~ /darwin/ && require_as
end
def linux_only(require_as)
RbConfig::CONFIG['host_os'] =~ /linux/ && require_as
end
gem 'rails', '4.2.3' gem 'rails', '4.2.3'
gem 'sqlite3' gem 'sqlite3'
@ -25,6 +17,8 @@ gem 'ancestry'
gem 'bcrypt' gem 'bcrypt'
gem 'pundit'
gem 'sdoc', '~> 0.4.0', group: :doc gem 'sdoc', '~> 0.4.0', group: :doc
group :development do group :development do

View file

@ -212,6 +212,8 @@ GEM
coderay (~> 1.1.0) coderay (~> 1.1.0)
method_source (~> 0.8.1) method_source (~> 0.8.1)
slop (~> 3.4) slop (~> 3.4)
pundit (1.0.1)
activesupport (>= 3.0.0)
quiet_assets (1.1.0) quiet_assets (1.1.0)
railties (>= 3.1, < 5.0) railties (>= 3.1, < 5.0)
rack (1.6.4) rack (1.6.4)
@ -387,6 +389,7 @@ DEPENDENCIES
launchy launchy
metric_fu metric_fu
pry pry
pundit
quiet_assets quiet_assets
rails (= 4.2.3) rails (= 4.2.3)
rspec-rails rspec-rails
@ -403,4 +406,4 @@ DEPENDENCIES
uglifier (>= 1.3.0) uglifier (>= 1.3.0)
BUNDLED WITH BUNDLED WITH
1.10.5 1.10.6

View file

@ -6,10 +6,15 @@ class ApplicationController < ActionController::Base
helper_method :current_session helper_method :current_session
helper_method :logged_in? helper_method :logged_in?
include Pundit
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
private private
def current_user def current_user
@current_user ||= User.find(current_session[:user_id]) if current_session @current_user ||= User.find(current_session[:user_id]) if current_session
@current_user ||= GuestUser.new
end end
def current_session def current_session
@ -17,6 +22,11 @@ class ApplicationController < ActionController::Base
end end
def logged_in? def logged_in?
!!current_user current_user.registered?
end
def user_not_authorized
flash[:alert] = 'You are not authorized to perform this action.'
redirect_to(request.referrer || root_path)
end end
end end

View file

@ -3,22 +3,29 @@ class CommentsController < ApplicationController
before_filter :set_comment, only: [:show, :edit, :update, :destroy] before_filter :set_comment, only: [:show, :edit, :update, :destroy]
before_filter :set_post before_filter :set_post
before_filter :set_subcreddit before_filter :set_subcreddit
after_action :verify_authorized
def show def show
@comments = @comment @comments = @comment
.subtree .subtree
.includes(:post, :user) .includes(:post, :user)
.arrange(order: :created_at) .arrange(order: :created_at)
authorize @comment
end end
def new def new
@comment = Comment.new(params[:parent_id]) @comment = Comment.new(params[:parent_id])
authorize @comment
end end
def create def create
@comment = @post.comments.build comment_params @comment = @post.comments.build comment_params
@comment.user = current_user @comment.user = current_user
authorize @comment
if @comment.save if @comment.save
flash[:notice] = 'Comment saved' flash[:notice] = 'Comment saved'
else else
@ -29,9 +36,12 @@ class CommentsController < ApplicationController
end end
def edit def edit
authorize @comment
end end
def update def update
authorize @comment
if @comment.update comment_params if @comment.update comment_params
redirect_to subcreddit_post_path(@subcreddit, @post), redirect_to subcreddit_post_path(@subcreddit, @post),
notice: 'Comment updated' notice: 'Comment updated'
@ -41,6 +51,8 @@ class CommentsController < ApplicationController
end end
def destroy def destroy
authorize @comment
@comment.destroy @comment.destroy
redirect_to subcreddit_post_path(@subcreddit, @post), redirect_to subcreddit_post_path(@subcreddit, @post),
notice: 'Comment deleted' notice: 'Comment deleted'

View file

@ -2,23 +2,32 @@
class PostsController < ApplicationController class PostsController < ApplicationController
before_filter :set_post, except: [:index, :new, :create] before_filter :set_post, except: [:index, :new, :create]
before_filter :set_subcreddit before_filter :set_subcreddit
after_action :verify_authorized
def index def index
@posts = Post.includes(:subcreddit, :user).all @posts = Post.includes(:subcreddit, :user).all
authorize Post
end end
def show def show
@comments = @post.comments.includes(:user).arrange(order: :created_at) @comments = @post.comments.includes(:user).arrange(order: :created_at)
authorize @post
end end
def new def new
@post = Post.new @post = Post.new
authorize @post
end end
def create def create
@post = @subcreddit.posts.build(post_params) @post = @subcreddit.posts.build(post_params)
@post.user = current_user @post.user = current_user
authorize @post
if @post.save if @post.save
redirect_to subcreddit_post_path(@subcreddit, @post), redirect_to subcreddit_post_path(@subcreddit, @post),
notice: 'Post created' notice: 'Post created'
@ -28,9 +37,12 @@ class PostsController < ApplicationController
end end
def edit def edit
authorize @post
end end
def update def update
authorize @post
if @post.update(post_params) if @post.update(post_params)
redirect_to subcreddit_post_path(@subcreddit, @post), redirect_to subcreddit_post_path(@subcreddit, @post),
notice: 'Post was updated' notice: 'Post was updated'
@ -40,6 +52,8 @@ class PostsController < ApplicationController
end end
def destroy def destroy
authorize @post
@post.destroy @post.destroy
redirect_to subcreddits_path(@subcreddit), notice: 'Post was deleted' redirect_to subcreddits_path(@subcreddit), notice: 'Post was deleted'

View file

@ -1,23 +1,32 @@
# controllers/subcreddits_controller.rb # controllers/subcreddits_controller.rb
class SubcredditsController < ApplicationController class SubcredditsController < ApplicationController
before_filter :set_subcreddit, only: [:show, :edit, :update] before_filter :set_subcreddit, only: [:show, :edit, :update]
after_action :verify_authorized
def index def index
@subcreddits = Subcreddit.all @subcreddits = Subcreddit.all
authorize Subcreddit
end end
def show def show
@posts = @subcreddit.posts @posts = @subcreddit.posts
authorize @subcreddit
end end
def new def new
@subcreddit = Subcreddit.new @subcreddit = Subcreddit.new
authorize @subcreddit
end end
def create def create
@subcreddit = Subcreddit.new(create_subcreddit_params) @subcreddit = Subcreddit.new(create_subcreddit_params)
@subcreddit.owner = current_user @subcreddit.owner = current_user
authorize @subcreddit
if @subcreddit.save if @subcreddit.save
redirect_to @subcreddit, notice: 'Subcreddit was created!' redirect_to @subcreddit, notice: 'Subcreddit was created!'
else else
@ -26,9 +35,12 @@ class SubcredditsController < ApplicationController
end end
def edit def edit
authorize @subcreddit
end end
def update def update
authorize @subcreddit
if @subcreddit.update(update_subcreddit_params) if @subcreddit.update(update_subcreddit_params)
redirect_to @subcreddit, notice: 'Subcreddit was updated!' redirect_to @subcreddit, notice: 'Subcreddit was updated!'
else else

6
app/models/guest_user.rb Normal file
View file

@ -0,0 +1,6 @@
# models/guest_user.rb
class GuestUser
def registered?
false
end
end

View file

@ -15,6 +15,10 @@ class User < ActiveRecord::Base
validates :username, presence: true, uniqueness: true, sluguuidless: true validates :username, presence: true, uniqueness: true, sluguuidless: true
validates :password, length: { minimum: 8 } validates :password, length: { minimum: 8 }
def registered?
true
end
private private
def downcase_email def downcase_email

View file

@ -0,0 +1,37 @@
# policies/application_policy.rb
class ApplicationPolicy
attr_reader :user, :record
def initialize(user, record)
@user = user
@record = record
end
def index?
false
end
def show?
false
end
def create?
false
end
def new?
create?
end
def update?
false
end
def edit?
update?
end
def destroy?
false
end
end

View file

@ -0,0 +1,22 @@
# policies/comment_policy.rb
class CommentPolicy < ApplicationPolicy
def index?
true
end
def show?
true
end
def create?
user.registered?
end
def update?
record.user == user
end
def destroy?
record.user == user
end
end

View file

@ -0,0 +1,22 @@
# policies/post_policy.rb
class PostPolicy < ApplicationPolicy
def index?
true
end
def show?
true
end
def create?
user.registered?
end
def update?
record.user == user
end
def destroy?
record.user == user
end
end

View file

@ -0,0 +1,18 @@
# policies/subcreddit_policy.rb
class SubcredditPolicy < ApplicationPolicy
def index?
true
end
def show?
true
end
def create?
user.registered?
end
def update?
record.owner == user
end
end

View file

@ -5,12 +5,14 @@
button.btn.btn-default type="button" button.btn.btn-default type="button"
span.glyphicon.glyphicon-search aria-hidden="true" span.glyphicon.glyphicon-search aria-hidden="true"
- if policy(:post).new?
- if @subcreddit && @subcreddit.id - if @subcreddit && @subcreddit.id
= link_to 'Submit a new link', new_subcreddit_post_path(@subcreddit), class: 'button btn btn-primary btn-block' = link_to 'Submit a new link', new_subcreddit_post_path(@subcreddit), class: 'button btn btn-primary btn-block'
= link_to 'Submit a new text post', new_subcreddit_post_path(@subcreddit), class: 'button btn btn-primary btn-block' = link_to 'Submit a new text post', new_subcreddit_post_path(@subcreddit), class: 'button btn btn-primary btn-block'
- if policy(:subcreddit).new?
= link_to 'Create your own subcreddit', new_subcreddit_path, class: 'button btn btn-primary btn-block' = link_to 'Create your own subcreddit', new_subcreddit_path, class: 'button btn btn-primary btn-block'
- if @subcreddit && @subcreddit.id - if @subcreddit && @subcreddit.id && policy(@subcreddit).edit?
.title Moderation Tools .title Moderation Tools
.box .box
ul ul

View file

@ -3,7 +3,8 @@
.alert.alert-info.in-page .alert.alert-info.in-page
p you are viewing a single comment's thread. p you are viewing a single comment's thread.
p #{link_to 'view the rest of the comments', subcreddit_post_path(@subcreddit, @post)} → p #{link_to 'view the rest of the comments', subcreddit_post_path(@subcreddit, @post)} →
= "Commenting as: #{current_user.username}" - if policy(:comment).new?
== render 'comments/form', subcreddit: @subcreddit, post: @post, comment: @post.comments.build, parent: @comment = "Commenting as: #{current_user.username}"
== render 'comments/form', subcreddit: @subcreddit, post: @post, comment: @post.comments.build, parent: @comment
.comments.contents .comments.contents
== nested_comments(@comments) == nested_comments(@comments)

View file

@ -4,7 +4,8 @@
.title= "all #{@post.comments_count} comments" .title= "all #{@post.comments_count} comments"
- else - else
.title= "no comments (yet)" .title= "no comments (yet)"
= "Commenting as: #{current_user.username}" - if policy(:comment).new?
== render 'comments/form', subcreddit: @subcreddit, post: @post, comment: @post.comments.build, parent: nil = "Commenting as: #{current_user.username}"
== render 'comments/form', subcreddit: @subcreddit, post: @post, comment: @post.comments.build, parent: nil
.comments.contents .comments.contents
== nested_comments(@comments) == nested_comments(@comments)

View file

@ -31,7 +31,7 @@ describe ApplicationController, type: :controller do
context 'when not logged in' do context 'when not logged in' do
it 'should return nil' do it 'should return nil' do
expect(controller.send(:current_user)).to be_nil expect(controller.send(:current_user)).to be_a(GuestUser)
end end
end end
end end

View file

@ -99,7 +99,8 @@ describe CommentsController, type: :controller do
end end
describe '#edit' do describe '#edit' do
let!(:comment) { create(:comment) } context 'when owner' do
let!(:comment) { create(:comment, user: user) }
before(:each) do before(:each) do
get :edit, get :edit,
id: comment, id: comment,
@ -117,12 +118,15 @@ describe CommentsController, type: :controller do
end end
end end
end end
end
context '#update' do context '#update' do
let!(:comment) { create(:comment) }
let(:data) { { content: 'Some edited comment content goes here' } } let(:data) { { content: 'Some edited comment content goes here' } }
context 'with valid data' do context 'with valid data' do
let!(:comment) { create(:comment, user: user) }
context 'when owner' do
before(:each) do before(:each) do
put :update, put :update,
id: comment, id: comment,
@ -166,9 +170,11 @@ describe CommentsController, type: :controller do
end end
end end
end end
end
context '#destroy' do context '#destroy' do
let!(:comment) { create(:comment) } context 'when owner' do
let!(:comment) { create(:comment, user: user) }
it 'should delete the post' do it 'should delete the post' do
delete :destroy, delete :destroy,
@ -186,7 +192,8 @@ describe CommentsController, type: :controller do
post_id: comment.post, post_id: comment.post,
subcreddit_id: comment.post.subcreddit subcreddit_id: comment.post.subcreddit
expect(response).to redirect_to(subcreddit_post_path(assigns(:subcreddit), expect(response)
.to redirect_to(subcreddit_post_path(assigns(:subcreddit),
assigns(:post))) assigns(:post)))
end end
@ -198,4 +205,5 @@ describe CommentsController, type: :controller do
expect(flash[:notice]).to be_present expect(flash[:notice]).to be_present
end end
end end
end
end end

View file

@ -94,7 +94,8 @@ describe PostsController, type: :controller do
end end
context '#edit' do context '#edit' do
let!(:post) { create(:post) } context 'when owner' do
let!(:post) { create(:post, user: user) }
before(:each) { get :edit, id: post, subcreddit_id: post.subcreddit } before(:each) { get :edit, id: post, subcreddit_id: post.subcreddit }
context 'with valid post' do context 'with valid post' do
@ -107,9 +108,9 @@ describe PostsController, type: :controller do
end end
end end
end end
end
context '#update' do context '#update' do
let!(:post) { create(:post) }
let(:data) do let(:data) do
{ {
title: 'New title', title: 'New title',
@ -117,6 +118,9 @@ describe PostsController, type: :controller do
} }
end end
context 'when owner' do
let!(:post) { create(:post, user: user) }
context 'with valid data' do context 'with valid data' do
before(:each) do before(:each) do
put :update, id: post, subcreddit_id: post.subcreddit, post: data put :update, id: post, subcreddit_id: post.subcreddit, post: data
@ -154,9 +158,11 @@ describe PostsController, type: :controller do
end end
end end
end end
end
context '#destroy' do context '#destroy' do
let!(:post) { create(:post, subcreddit: subcreddit) } context 'when owner' do
let!(:post) { create(:post, user: user, subcreddit: subcreddit) }
it 'should delete the post' do it 'should delete the post' do
expect { delete :destroy, subcreddit_id: subcreddit, id: post } expect { delete :destroy, subcreddit_id: subcreddit, id: post }
@ -174,4 +180,5 @@ describe PostsController, type: :controller do
expect(flash[:notice]).to be_present expect(flash[:notice]).to be_present
end end
end end
end
end end

View file

@ -97,7 +97,8 @@ describe SubcredditsController, type: :controller do
describe '#edit' do describe '#edit' do
context 'with valid subcreddit' do context 'with valid subcreddit' do
let(:subcreddit) { create(:subcreddit) } context 'when owner' do
let(:subcreddit) { create(:subcreddit, owner: user) }
it 'should assign @subcreddit to the existing subcreddit' do it 'should assign @subcreddit to the existing subcreddit' do
get :edit, id: subcreddit get :edit, id: subcreddit
@ -112,9 +113,9 @@ describe SubcredditsController, type: :controller do
end end
end end
end end
end
describe '#update' do describe '#update' do
let(:subcreddit) { create(:subcreddit) }
let(:data) do let(:data) do
{ {
closed: '1' closed: '1'
@ -122,6 +123,9 @@ describe SubcredditsController, type: :controller do
end end
context 'wth valid data' do context 'wth valid data' do
context 'when owner' do
let(:subcreddit) { create(:subcreddit, owner: user) }
it 'should assign @subcreddit to the existing subcreddit' do it 'should assign @subcreddit to the existing subcreddit' do
put :update, id: subcreddit, subcreddit: data put :update, id: subcreddit, subcreddit: data
@ -146,7 +150,6 @@ describe SubcredditsController, type: :controller do
expect(flash[:notice]).to be_present expect(flash[:notice]).to be_present
end end
end
context 'with invalid data' do context 'with invalid data' do
before(:each) { data[:closed] = 'bad' } before(:each) { data[:closed] = 'bad' }
@ -158,4 +161,6 @@ describe SubcredditsController, type: :controller do
end end
end end
end end
end
end
end end

View file

@ -3,15 +3,20 @@ require 'rails_helper'
describe 'Edit Comment', type: :feature do describe 'Edit Comment', type: :feature do
let!(:user) { create(:user) } let!(:user) { create(:user) }
let!(:post) { create(:post) } let!(:post) { create(:post) }
let!(:comment) { create(:comment, post: post, user: user) }
context 'when signed in' do context 'when signed in' do
let(:content) { 'Some different data' } let!(:comment) { create(:comment, post: post, user: user) }
before(:each) { signin(user: user) } before(:each) { signin(user: user) }
context 'when owner' do
let(:content) { 'Some different data' }
context 'with valid data' do context 'with valid data' do
before(:each) do before(:each) do
visit edit_subcreddit_post_comment_path(post.subcreddit, post, comment) visit edit_subcreddit_post_comment_path(post.subcreddit,
post,
comment)
fill_in :comment_content, with: content fill_in :comment_content, with: content
@ -27,4 +32,25 @@ describe 'Edit Comment', type: :feature do
end end
end end
end end
context 'when not owner' do
let!(:comment) { create(:comment, post: post) }
it 'should not allow editing of comment' do
visit edit_subcreddit_post_comment_path(post.subcreddit, post, comment)
expect(page).to have_content('not authorized')
end
end
end
context 'when not signed in' do
let!(:comment) { create(:comment, post: post) }
it 'should not allow editing of comment' do
visit edit_subcreddit_post_comment_path(post.subcreddit, post, comment)
expect(page).to have_content('not authorized')
end
end
end end

View file

@ -1,14 +1,17 @@
require 'rails_helper' require 'rails_helper'
describe 'Edit Post', type: :feature do describe 'Edit Post', type: :feature do
let!(:subcreddit) { create(:subcreddit) }
context 'when signed in' do context 'when signed in' do
let!(:user) { create(:user) } let!(:user) { create(:user) }
let!(:subcreddit) { create(:subcreddit) }
let!(:post) { create(:post, subcreddit: subcreddit, user: user) }
let(:new_post) { build_stubbed(:post) } let(:new_post) { build_stubbed(:post) }
before(:each) { signin(user: user) } before(:each) { signin(user: user) }
context 'when owner' do
let!(:post) { create(:post, subcreddit: subcreddit, user: user) }
context 'with valid data' do context 'with valid data' do
before(:each) do before(:each) do
visit edit_subcreddit_post_path(subcreddit, post) visit edit_subcreddit_post_path(subcreddit, post)
@ -30,4 +33,26 @@ describe 'Edit Post', type: :feature do
end end
end end
end end
context 'when not owner' do
let!(:post) { create(:post, subcreddit: subcreddit) }
it 'should notify user that they cannot edit' do
visit edit_subcreddit_post_path(subcreddit, post)
expect(page).to have_content 'not authorized'
end
end
end
context 'when not signed in' do
let!(:user) { GuestUser.new }
let!(:post) { create(:post, subcreddit: subcreddit) }
it 'should notify user they cannot edit' do
visit edit_subcreddit_post_path(subcreddit, post)
expect(page).to have_content 'not authorized'
end
end
end end

View file

@ -1,9 +1,10 @@
require 'rails_helper' require 'rails_helper'
describe 'New Post', type: :feature do describe 'New Post', type: :feature do
let!(:subcreddit) { create(:subcreddit) }
context 'when signed in' do context 'when signed in' do
let!(:user) { create(:user) } let!(:user) { create(:user) }
let!(:subcreddit) { create(:subcreddit) }
let!(:post) { build(:post, subcreddit: subcreddit) } let!(:post) { build(:post, subcreddit: subcreddit) }
before(:each) { signin(user: user) } before(:each) { signin(user: user) }
@ -46,4 +47,15 @@ describe 'New Post', type: :feature do
end end
end end
end end
context 'when not signed in' do
let!(:user) { GuestUser.new }
let!(:post) { create(:post, subcreddit: subcreddit) }
it 'should notify user they cannot create' do
visit new_subcreddit_post_path(subcreddit)
expect(page).to have_content 'not authorized'
end
end
end end

View file

@ -4,8 +4,13 @@ describe 'Edit Subcreddit', type: :feature do
before(:each) { signout } before(:each) { signout }
context 'when logged in' do context 'when logged in' do
let!(:user) { create(:user) }
before(:each) { signin(user: user) }
context 'when user is owner' do
let!(:subcreddit) { create(:subcreddit, owner: user) }
context 'when board is open' do context 'when board is open' do
let!(:subcreddit) { create(:subcreddit) }
before(:each) do before(:each) do
visit subcreddits_path visit subcreddits_path
click_link 'Edit' click_link 'Edit'
@ -23,7 +28,10 @@ describe 'Edit Subcreddit', type: :feature do
end end
context 'when board is closed' do context 'when board is closed' do
let!(:subcreddit) { create(:subcreddit, closed_at: Time.now) } let!(:subcreddit) do
create(:subcreddit, owner: user, closed_at: Time.now)
end
before(:each) do before(:each) do
visit subcreddits_path visit subcreddits_path
click_link 'Edit' click_link 'Edit'
@ -36,4 +44,20 @@ describe 'Edit Subcreddit', type: :feature do
end end
end end
end end
context 'when not owner' do
let!(:subcreddit) { create(:subcreddit) }
it 'should not allow editing of subcreddit' do
visit subcreddits_path
click_link 'Edit'
expect(page).to have_content('not authorized')
end
end
end
context 'when not logged in' do
end
end end

View file

@ -4,7 +4,11 @@ describe 'New Subcreddit', type: :feature do
before(:each) { signout } before(:each) { signout }
context 'when not signed in' do context 'when not signed in' do
it 'should not be able to create a new subcreddit' it 'should not be able to create a new subcreddit' do
visit new_subcreddit_path
expect(page).to have_content('not authorized')
end
end end
context 'when signed in' do context 'when signed in' do

View file

@ -0,0 +1,15 @@
require 'rails_helper'
describe ApplicationPolicy do
subject { ApplicationPolicy.new(user, object) }
let(:user) { create(:user) }
let(:object) { double('Object') }
it { should_not grant(:index) }
it { should_not grant(:show) }
it { should_not grant(:new) }
it { should_not grant(:create) }
it { should_not grant(:edit) }
it { should_not grant(:update) }
it { should_not grant(:destroy) }
end

View file

@ -0,0 +1,48 @@
require 'rails_helper'
describe CommentPolicy do
subject { CommentPolicy.new(user, comment) }
context 'when user is a guest' do
let(:comment) { create(:comment) }
let(:user) { GuestUser.new }
it { should grant(:index) }
it { should grant(:show) }
it { should_not grant(:new) }
it { should_not grant(:create) }
it { should_not grant(:edit) }
it { should_not grant(:update) }
it { should_not grant(:destroy) }
end
context 'when user is registered' do
let(:user) { create(:user) }
context 'when not owner' do
let(:comment) { create(:comment) }
it { should grant(:index) }
it { should grant(:show) }
it { should grant(:new) }
it { should grant(:create) }
it { should_not grant(:edit) }
it { should_not grant(:update) }
it { should_not grant(:destroy) }
end
context 'when owner' do
let(:comment) { create(:comment, user: user) }
it { should grant(:index) }
it { should grant(:show) }
it { should grant(:new) }
it { should grant(:create) }
it { should grant(:edit) }
it { should grant(:update) }
it { should grant(:destroy) }
end
end
end

View file

@ -0,0 +1,48 @@
require 'rails_helper'
describe PostPolicy do
subject { PostPolicy.new(user, post) }
context 'when user is a guest' do
let(:post) { create(:post) }
let(:user) { GuestUser.new }
it { should grant(:index) }
it { should grant(:show) }
it { should_not grant(:new) }
it { should_not grant(:create) }
it { should_not grant(:edit) }
it { should_not grant(:update) }
it { should_not grant(:destroy) }
end
context 'when user is registered' do
let(:user) { create(:user) }
context 'when not owner' do
let(:post) { create(:post) }
it { should grant(:index) }
it { should grant(:show) }
it { should grant(:new) }
it { should grant(:create) }
it { should_not grant(:edit) }
it { should_not grant(:update) }
it { should_not grant(:destroy) }
end
context 'when owner' do
let(:post) { create(:post, user: user) }
it { should grant(:index) }
it { should grant(:show) }
it { should grant(:new) }
it { should grant(:create) }
it { should grant(:edit) }
it { should grant(:update) }
it { should grant(:destroy) }
end
end
end

View file

@ -0,0 +1,49 @@
require 'rails_helper'
describe SubcredditPolicy do
subject { SubcredditPolicy.new(user, subcreddit) }
context 'when user is a guest' do
let(:subcreddit) { create(:subcreddit) }
let(:user) { GuestUser.new }
it { should grant(:index) }
it { should grant(:show) }
it { should_not grant(:new) }
it { should_not grant(:create) }
it { should_not grant(:edit) }
it { should_not grant(:update) }
it { should_not grant(:destroy) }
end
context 'when user is registered' do
let(:user) { create(:user) }
context 'when not owner' do
let(:subcreddit) { create(:subcreddit) }
it { should grant(:index) }
it { should grant(:show) }
it { should grant(:new) }
it { should grant(:create) }
it { should_not grant(:edit) }
it { should_not grant(:update) }
it { should_not grant(:destroy) }
end
context 'when owner' do
let(:subcreddit) { create(:subcreddit, owner: user) }
it { should grant(:index) }
it { should grant(:show) }
it { should grant(:new) }
it { should grant(:create) }
it { should grant(:edit) }
it { should grant(:update) }
it { should_not grant(:destroy) }
end
end
end

View file

@ -12,11 +12,13 @@ require 'rspec/rails'
require 'shoulda/matchers' require 'shoulda/matchers'
require 'capybara/rails' require 'capybara/rails'
require 'capybara/rspec' require 'capybara/rspec'
require 'pundit/rspec'
require 'support/capybara' require 'support/capybara'
require 'support/database_cleaner' require 'support/database_cleaner'
require 'support/factory_girl' require 'support/factory_girl'
require 'support/helpers' require 'support/helpers'
require 'support/pundit_matcher'
ActiveRecord::Migration.maintain_test_schema! ActiveRecord::Migration.maintain_test_schema!

View file

@ -0,0 +1,15 @@
RSpec::Matchers.define :grant do |action|
match do |policy|
policy.public_send("#{action}?")
end
failure_message do |policy|
"#{policy.class} does not permit #{action} on #{policy.record} "
+ "for #{policy.user.inspect}."
end
failure_message_when_negated do |policy|
"#{policy.class} does not forbid #{action} on #{policy.record} "
+ "for #{policy.user.inspect}."
end
end