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:
commit
1f9788309b
31 changed files with 678 additions and 231 deletions
|
@ -4,4 +4,5 @@ test:
|
|||
- apt-get install -y nodejs libqtwebkit-dev qt4-qmake sqlite3 libsqlite3-dev
|
||||
- bundle install --path /cache
|
||||
- bundle exec rake db:create RAILS_ENV=test
|
||||
- bundle exec rake db:test:prepare
|
||||
- bundle exec rspec
|
||||
|
|
10
Gemfile
10
Gemfile
|
@ -1,13 +1,5 @@
|
|||
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 'sqlite3'
|
||||
|
||||
|
@ -25,6 +17,8 @@ gem 'ancestry'
|
|||
|
||||
gem 'bcrypt'
|
||||
|
||||
gem 'pundit'
|
||||
|
||||
gem 'sdoc', '~> 0.4.0', group: :doc
|
||||
|
||||
group :development do
|
||||
|
|
|
@ -212,6 +212,8 @@ GEM
|
|||
coderay (~> 1.1.0)
|
||||
method_source (~> 0.8.1)
|
||||
slop (~> 3.4)
|
||||
pundit (1.0.1)
|
||||
activesupport (>= 3.0.0)
|
||||
quiet_assets (1.1.0)
|
||||
railties (>= 3.1, < 5.0)
|
||||
rack (1.6.4)
|
||||
|
@ -387,6 +389,7 @@ DEPENDENCIES
|
|||
launchy
|
||||
metric_fu
|
||||
pry
|
||||
pundit
|
||||
quiet_assets
|
||||
rails (= 4.2.3)
|
||||
rspec-rails
|
||||
|
@ -403,4 +406,4 @@ DEPENDENCIES
|
|||
uglifier (>= 1.3.0)
|
||||
|
||||
BUNDLED WITH
|
||||
1.10.5
|
||||
1.10.6
|
||||
|
|
|
@ -6,10 +6,15 @@ class ApplicationController < ActionController::Base
|
|||
helper_method :current_session
|
||||
helper_method :logged_in?
|
||||
|
||||
include Pundit
|
||||
|
||||
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
|
||||
|
||||
private
|
||||
|
||||
def current_user
|
||||
@current_user ||= User.find(current_session[:user_id]) if current_session
|
||||
@current_user ||= GuestUser.new
|
||||
end
|
||||
|
||||
def current_session
|
||||
|
@ -17,6 +22,11 @@ class ApplicationController < ActionController::Base
|
|||
end
|
||||
|
||||
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
|
||||
|
|
|
@ -3,22 +3,29 @@ class CommentsController < ApplicationController
|
|||
before_filter :set_comment, only: [:show, :edit, :update, :destroy]
|
||||
before_filter :set_post
|
||||
before_filter :set_subcreddit
|
||||
after_action :verify_authorized
|
||||
|
||||
def show
|
||||
@comments = @comment
|
||||
.subtree
|
||||
.includes(:post, :user)
|
||||
.arrange(order: :created_at)
|
||||
|
||||
authorize @comment
|
||||
end
|
||||
|
||||
def new
|
||||
@comment = Comment.new(params[:parent_id])
|
||||
|
||||
authorize @comment
|
||||
end
|
||||
|
||||
def create
|
||||
@comment = @post.comments.build comment_params
|
||||
@comment.user = current_user
|
||||
|
||||
authorize @comment
|
||||
|
||||
if @comment.save
|
||||
flash[:notice] = 'Comment saved'
|
||||
else
|
||||
|
@ -29,9 +36,12 @@ class CommentsController < ApplicationController
|
|||
end
|
||||
|
||||
def edit
|
||||
authorize @comment
|
||||
end
|
||||
|
||||
def update
|
||||
authorize @comment
|
||||
|
||||
if @comment.update comment_params
|
||||
redirect_to subcreddit_post_path(@subcreddit, @post),
|
||||
notice: 'Comment updated'
|
||||
|
@ -41,6 +51,8 @@ class CommentsController < ApplicationController
|
|||
end
|
||||
|
||||
def destroy
|
||||
authorize @comment
|
||||
|
||||
@comment.destroy
|
||||
redirect_to subcreddit_post_path(@subcreddit, @post),
|
||||
notice: 'Comment deleted'
|
||||
|
|
|
@ -2,23 +2,32 @@
|
|||
class PostsController < ApplicationController
|
||||
before_filter :set_post, except: [:index, :new, :create]
|
||||
before_filter :set_subcreddit
|
||||
after_action :verify_authorized
|
||||
|
||||
def index
|
||||
@posts = Post.includes(:subcreddit, :user).all
|
||||
|
||||
authorize Post
|
||||
end
|
||||
|
||||
def show
|
||||
@comments = @post.comments.includes(:user).arrange(order: :created_at)
|
||||
|
||||
authorize @post
|
||||
end
|
||||
|
||||
def new
|
||||
@post = Post.new
|
||||
|
||||
authorize @post
|
||||
end
|
||||
|
||||
def create
|
||||
@post = @subcreddit.posts.build(post_params)
|
||||
@post.user = current_user
|
||||
|
||||
authorize @post
|
||||
|
||||
if @post.save
|
||||
redirect_to subcreddit_post_path(@subcreddit, @post),
|
||||
notice: 'Post created'
|
||||
|
@ -28,9 +37,12 @@ class PostsController < ApplicationController
|
|||
end
|
||||
|
||||
def edit
|
||||
authorize @post
|
||||
end
|
||||
|
||||
def update
|
||||
authorize @post
|
||||
|
||||
if @post.update(post_params)
|
||||
redirect_to subcreddit_post_path(@subcreddit, @post),
|
||||
notice: 'Post was updated'
|
||||
|
@ -40,6 +52,8 @@ class PostsController < ApplicationController
|
|||
end
|
||||
|
||||
def destroy
|
||||
authorize @post
|
||||
|
||||
@post.destroy
|
||||
|
||||
redirect_to subcreddits_path(@subcreddit), notice: 'Post was deleted'
|
||||
|
|
|
@ -1,23 +1,32 @@
|
|||
# controllers/subcreddits_controller.rb
|
||||
class SubcredditsController < ApplicationController
|
||||
before_filter :set_subcreddit, only: [:show, :edit, :update]
|
||||
after_action :verify_authorized
|
||||
|
||||
def index
|
||||
@subcreddits = Subcreddit.all
|
||||
|
||||
authorize Subcreddit
|
||||
end
|
||||
|
||||
def show
|
||||
@posts = @subcreddit.posts
|
||||
|
||||
authorize @subcreddit
|
||||
end
|
||||
|
||||
def new
|
||||
@subcreddit = Subcreddit.new
|
||||
|
||||
authorize @subcreddit
|
||||
end
|
||||
|
||||
def create
|
||||
@subcreddit = Subcreddit.new(create_subcreddit_params)
|
||||
@subcreddit.owner = current_user
|
||||
|
||||
authorize @subcreddit
|
||||
|
||||
if @subcreddit.save
|
||||
redirect_to @subcreddit, notice: 'Subcreddit was created!'
|
||||
else
|
||||
|
@ -26,9 +35,12 @@ class SubcredditsController < ApplicationController
|
|||
end
|
||||
|
||||
def edit
|
||||
authorize @subcreddit
|
||||
end
|
||||
|
||||
def update
|
||||
authorize @subcreddit
|
||||
|
||||
if @subcreddit.update(update_subcreddit_params)
|
||||
redirect_to @subcreddit, notice: 'Subcreddit was updated!'
|
||||
else
|
||||
|
|
6
app/models/guest_user.rb
Normal file
6
app/models/guest_user.rb
Normal file
|
@ -0,0 +1,6 @@
|
|||
# models/guest_user.rb
|
||||
class GuestUser
|
||||
def registered?
|
||||
false
|
||||
end
|
||||
end
|
|
@ -15,6 +15,10 @@ class User < ActiveRecord::Base
|
|||
validates :username, presence: true, uniqueness: true, sluguuidless: true
|
||||
validates :password, length: { minimum: 8 }
|
||||
|
||||
def registered?
|
||||
true
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def downcase_email
|
||||
|
|
37
app/policies/application_policy.rb
Normal file
37
app/policies/application_policy.rb
Normal 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
|
22
app/policies/comment_policy.rb
Normal file
22
app/policies/comment_policy.rb
Normal 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
|
22
app/policies/post_policy.rb
Normal file
22
app/policies/post_policy.rb
Normal 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
|
18
app/policies/subcreddit_policy.rb
Normal file
18
app/policies/subcreddit_policy.rb
Normal 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
|
|
@ -5,12 +5,14 @@
|
|||
button.btn.btn-default type="button"
|
||||
span.glyphicon.glyphicon-search aria-hidden="true"
|
||||
|
||||
- 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 text post', new_subcreddit_post_path(@subcreddit), class: 'button btn btn-primary btn-block'
|
||||
= link_to 'Create your own subcreddit', new_subcreddit_path, class: 'button btn btn-primary btn-block'
|
||||
- if policy(:post).new?
|
||||
- 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 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'
|
||||
|
||||
- if @subcreddit && @subcreddit.id
|
||||
- if @subcreddit && @subcreddit.id && policy(@subcreddit).edit?
|
||||
.title Moderation Tools
|
||||
.box
|
||||
ul
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
.alert.alert-info.in-page
|
||||
p you are viewing a single comment's thread.
|
||||
p #{link_to 'view the rest of the comments', subcreddit_post_path(@subcreddit, @post)} →
|
||||
= "Commenting as: #{current_user.username}"
|
||||
== render 'comments/form', subcreddit: @subcreddit, post: @post, comment: @post.comments.build, parent: @comment
|
||||
- if policy(:comment).new?
|
||||
= "Commenting as: #{current_user.username}"
|
||||
== render 'comments/form', subcreddit: @subcreddit, post: @post, comment: @post.comments.build, parent: @comment
|
||||
.comments.contents
|
||||
== nested_comments(@comments)
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
.title= "all #{@post.comments_count} comments"
|
||||
- else
|
||||
.title= "no comments (yet)"
|
||||
= "Commenting as: #{current_user.username}"
|
||||
== render 'comments/form', subcreddit: @subcreddit, post: @post, comment: @post.comments.build, parent: nil
|
||||
- if policy(:comment).new?
|
||||
= "Commenting as: #{current_user.username}"
|
||||
== render 'comments/form', subcreddit: @subcreddit, post: @post, comment: @post.comments.build, parent: nil
|
||||
.comments.contents
|
||||
== nested_comments(@comments)
|
||||
|
|
|
@ -31,7 +31,7 @@ describe ApplicationController, type: :controller do
|
|||
|
||||
context 'when not logged in' 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
|
||||
|
|
|
@ -99,103 +99,111 @@ describe CommentsController, type: :controller do
|
|||
end
|
||||
|
||||
describe '#edit' do
|
||||
let!(:comment) { create(:comment) }
|
||||
before(:each) do
|
||||
get :edit,
|
||||
id: comment,
|
||||
post_id: comment.post,
|
||||
subcreddit_id: comment.post.subcreddit
|
||||
end
|
||||
|
||||
context 'with valid comment' do
|
||||
it 'should render :edit' do
|
||||
expect(response).to render_template(:edit)
|
||||
context 'when owner' do
|
||||
let!(:comment) { create(:comment, user: user) }
|
||||
before(:each) do
|
||||
get :edit,
|
||||
id: comment,
|
||||
post_id: comment.post,
|
||||
subcreddit_id: comment.post.subcreddit
|
||||
end
|
||||
|
||||
it 'should assign correct Comment to @comment' do
|
||||
expect(assigns(:comment)).to eq(comment)
|
||||
context 'with valid comment' do
|
||||
it 'should render :edit' do
|
||||
expect(response).to render_template(:edit)
|
||||
end
|
||||
|
||||
it 'should assign correct Comment to @comment' do
|
||||
expect(assigns(:comment)).to eq(comment)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context '#update' do
|
||||
let!(:comment) { create(:comment) }
|
||||
let(:data) { { content: 'Some edited comment content goes here' } }
|
||||
|
||||
context 'with valid data' do
|
||||
before(:each) do
|
||||
put :update,
|
||||
id: comment,
|
||||
post_id: comment.post,
|
||||
subcreddit_id: comment.post.subcreddit,
|
||||
comment: data
|
||||
let!(:comment) { create(:comment, user: user) }
|
||||
|
||||
context 'when owner' do
|
||||
before(:each) do
|
||||
put :update,
|
||||
id: comment,
|
||||
post_id: comment.post,
|
||||
subcreddit_id: comment.post.subcreddit,
|
||||
comment: data
|
||||
end
|
||||
|
||||
it 'should assign correct Comment to @comment' do
|
||||
expect(assigns(:comment)).to eq(comment)
|
||||
end
|
||||
|
||||
it 'should update the comment' do
|
||||
comment.reload
|
||||
|
||||
expect(comment.content).to eq(data[:content])
|
||||
end
|
||||
|
||||
it 'should redirect to the post' do
|
||||
expect(response)
|
||||
.to redirect_to(subcreddit_post_path(assigns(:post).subcreddit,
|
||||
assigns(:post)))
|
||||
end
|
||||
|
||||
it 'should display a notice flash message' do
|
||||
expect(flash[:notice]).to be_present
|
||||
end
|
||||
end
|
||||
|
||||
it 'should assign correct Comment to @comment' do
|
||||
expect(assigns(:comment)).to eq(comment)
|
||||
end
|
||||
context 'with invalid data' do
|
||||
before(:each) { data[:content] = '' }
|
||||
|
||||
it 'should update the comment' do
|
||||
comment.reload
|
||||
it 'should render :edit' do
|
||||
put :update,
|
||||
id: comment,
|
||||
post_id: comment.post,
|
||||
subcreddit_id: comment.post.subcreddit,
|
||||
comment: data
|
||||
|
||||
expect(comment.content).to eq(data[:content])
|
||||
end
|
||||
|
||||
it 'should redirect to the post' do
|
||||
expect(response)
|
||||
.to redirect_to(subcreddit_post_path(assigns(:post).subcreddit,
|
||||
assigns(:post)))
|
||||
end
|
||||
|
||||
it 'should display a notice flash message' do
|
||||
expect(flash[:notice]).to be_present
|
||||
end
|
||||
end
|
||||
|
||||
context 'with invalid data' do
|
||||
before(:each) { data[:content] = '' }
|
||||
|
||||
it 'should render :edit' do
|
||||
put :update,
|
||||
id: comment,
|
||||
post_id: comment.post,
|
||||
subcreddit_id: comment.post.subcreddit,
|
||||
comment: data
|
||||
|
||||
expect(response).to render_template(:edit)
|
||||
expect(response).to render_template(:edit)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context '#destroy' do
|
||||
let!(:comment) { create(:comment) }
|
||||
context 'when owner' do
|
||||
let!(:comment) { create(:comment, user: user) }
|
||||
|
||||
it 'should delete the post' do
|
||||
delete :destroy,
|
||||
id: comment,
|
||||
post_id: comment.post,
|
||||
subcreddit_id: comment.post.subcreddit
|
||||
it 'should delete the post' do
|
||||
delete :destroy,
|
||||
id: comment,
|
||||
post_id: comment.post,
|
||||
subcreddit_id: comment.post.subcreddit
|
||||
|
||||
comment.reload
|
||||
expect(comment.destroyed?).to be(true)
|
||||
end
|
||||
comment.reload
|
||||
expect(comment.destroyed?).to be(true)
|
||||
end
|
||||
|
||||
it 'should redirect to the post' do
|
||||
delete :destroy,
|
||||
id: comment,
|
||||
post_id: comment.post,
|
||||
subcreddit_id: comment.post.subcreddit
|
||||
it 'should redirect to the post' do
|
||||
delete :destroy,
|
||||
id: comment,
|
||||
post_id: comment.post,
|
||||
subcreddit_id: comment.post.subcreddit
|
||||
|
||||
expect(response).to redirect_to(subcreddit_post_path(assigns(:subcreddit),
|
||||
assigns(:post)))
|
||||
end
|
||||
expect(response)
|
||||
.to redirect_to(subcreddit_post_path(assigns(:subcreddit),
|
||||
assigns(:post)))
|
||||
end
|
||||
|
||||
it 'should send a notice flash message' do
|
||||
delete :destroy,
|
||||
id: comment,
|
||||
post_id: comment.post,
|
||||
subcreddit_id: comment.post.subcreddit
|
||||
expect(flash[:notice]).to be_present
|
||||
it 'should send a notice flash message' do
|
||||
delete :destroy,
|
||||
id: comment,
|
||||
post_id: comment.post,
|
||||
subcreddit_id: comment.post.subcreddit
|
||||
expect(flash[:notice]).to be_present
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -94,22 +94,23 @@ describe PostsController, type: :controller do
|
|||
end
|
||||
|
||||
context '#edit' do
|
||||
let!(:post) { create(:post) }
|
||||
before(:each) { get :edit, id: post, subcreddit_id: post.subcreddit }
|
||||
context 'when owner' do
|
||||
let!(:post) { create(:post, user: user) }
|
||||
before(:each) { get :edit, id: post, subcreddit_id: post.subcreddit }
|
||||
|
||||
context 'with valid post' do
|
||||
it 'should render :edit' do
|
||||
expect(response).to render_template(:edit)
|
||||
end
|
||||
context 'with valid post' do
|
||||
it 'should render :edit' do
|
||||
expect(response).to render_template(:edit)
|
||||
end
|
||||
|
||||
it 'should assign correct Post to @post' do
|
||||
expect(assigns(:post)).to eq(post)
|
||||
it 'should assign correct Post to @post' do
|
||||
expect(assigns(:post)).to eq(post)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context '#update' do
|
||||
let!(:post) { create(:post) }
|
||||
let(:data) do
|
||||
{
|
||||
title: 'New title',
|
||||
|
@ -117,61 +118,67 @@ describe PostsController, type: :controller do
|
|||
}
|
||||
end
|
||||
|
||||
context 'with valid data' do
|
||||
before(:each) do
|
||||
put :update, id: post, subcreddit_id: post.subcreddit, post: data
|
||||
context 'when owner' do
|
||||
let!(:post) { create(:post, user: user) }
|
||||
|
||||
context 'with valid data' do
|
||||
before(:each) do
|
||||
put :update, id: post, subcreddit_id: post.subcreddit, post: data
|
||||
end
|
||||
|
||||
it 'should assign correct Post to @post' do
|
||||
expect(assigns(:post)).to eq(post)
|
||||
end
|
||||
|
||||
it 'should update the post' do
|
||||
post.reload
|
||||
|
||||
expect(post.title).to eq(data[:title])
|
||||
expect(post.content).to eq(data[:content])
|
||||
end
|
||||
|
||||
it 'should redirect to the post' do
|
||||
expect(response)
|
||||
.to redirect_to(subcreddit_post_path(assigns(:post).subcreddit,
|
||||
assigns(:post)))
|
||||
end
|
||||
|
||||
it 'should display a notice flash message' do
|
||||
expect(flash[:notice]).to be_present
|
||||
end
|
||||
end
|
||||
|
||||
it 'should assign correct Post to @post' do
|
||||
expect(assigns(:post)).to eq(post)
|
||||
end
|
||||
context 'with invalid data' do
|
||||
before(:each) { data[:title] = '' }
|
||||
|
||||
it 'should update the post' do
|
||||
post.reload
|
||||
it 'should render :edit' do
|
||||
put :update, id: post, subcreddit_id: post.subcreddit, post: data
|
||||
|
||||
expect(post.title).to eq(data[:title])
|
||||
expect(post.content).to eq(data[:content])
|
||||
end
|
||||
|
||||
it 'should redirect to the post' do
|
||||
expect(response)
|
||||
.to redirect_to(subcreddit_post_path(assigns(:post).subcreddit,
|
||||
assigns(:post)))
|
||||
end
|
||||
|
||||
it 'should display a notice flash message' do
|
||||
expect(flash[:notice]).to be_present
|
||||
end
|
||||
end
|
||||
|
||||
context 'with invalid data' do
|
||||
before(:each) { data[:title] = '' }
|
||||
|
||||
it 'should render :edit' do
|
||||
put :update, id: post, subcreddit_id: post.subcreddit, post: data
|
||||
|
||||
expect(response).to render_template(:edit)
|
||||
expect(response).to render_template(:edit)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
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
|
||||
expect { delete :destroy, subcreddit_id: subcreddit, id: post }
|
||||
.to change(Post, :count).by(-1)
|
||||
end
|
||||
it 'should delete the post' do
|
||||
expect { delete :destroy, subcreddit_id: subcreddit, id: post }
|
||||
.to change(Post, :count).by(-1)
|
||||
end
|
||||
|
||||
it 'should redirect to the subcreddit index' do
|
||||
expect(delete :destroy, subcreddit_id: subcreddit, id: post)
|
||||
.to redirect_to(subcreddits_path(subcreddit))
|
||||
end
|
||||
it 'should redirect to the subcreddit index' do
|
||||
expect(delete :destroy, subcreddit_id: subcreddit, id: post)
|
||||
.to redirect_to(subcreddits_path(subcreddit))
|
||||
end
|
||||
|
||||
it 'should flash notify that the post was deleted' do
|
||||
delete :destroy, subcreddit_id: subcreddit, id: post
|
||||
it 'should flash notify that the post was deleted' do
|
||||
delete :destroy, subcreddit_id: subcreddit, id: post
|
||||
|
||||
expect(flash[:notice]).to be_present
|
||||
expect(flash[:notice]).to be_present
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -97,24 +97,25 @@ describe SubcredditsController, type: :controller do
|
|||
|
||||
describe '#edit' 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
|
||||
get :edit, id: subcreddit
|
||||
it 'should assign @subcreddit to the existing subcreddit' do
|
||||
get :edit, id: subcreddit
|
||||
|
||||
expect(assigns(:subcreddit)).to eq(subcreddit)
|
||||
end
|
||||
expect(assigns(:subcreddit)).to eq(subcreddit)
|
||||
end
|
||||
|
||||
it 'should render :edit' do
|
||||
get :edit, id: subcreddit
|
||||
it 'should render :edit' do
|
||||
get :edit, id: subcreddit
|
||||
|
||||
expect(response).to render_template(:edit)
|
||||
expect(response).to render_template(:edit)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#update' do
|
||||
let(:subcreddit) { create(:subcreddit) }
|
||||
let(:data) do
|
||||
{
|
||||
closed: '1'
|
||||
|
@ -122,39 +123,43 @@ describe SubcredditsController, type: :controller do
|
|||
end
|
||||
|
||||
context 'wth valid data' do
|
||||
it 'should assign @subcreddit to the existing subcreddit' do
|
||||
put :update, id: subcreddit, subcreddit: data
|
||||
context 'when owner' do
|
||||
let(:subcreddit) { create(:subcreddit, owner: user) }
|
||||
|
||||
expect(assigns(:subcreddit)).to eq(subcreddit)
|
||||
end
|
||||
it 'should assign @subcreddit to the existing subcreddit' do
|
||||
put :update, id: subcreddit, subcreddit: data
|
||||
|
||||
it 'should update the subcreddit' do
|
||||
put :update, id: subcreddit, subcreddit: data
|
||||
subcreddit.reload
|
||||
expect(assigns(:subcreddit)).to eq(subcreddit)
|
||||
end
|
||||
|
||||
expect(subcreddit.closed_at).to_not eq(nil)
|
||||
end
|
||||
it 'should update the subcreddit' do
|
||||
put :update, id: subcreddit, subcreddit: data
|
||||
subcreddit.reload
|
||||
|
||||
it 'should redirect to the subcreddit' do
|
||||
put :update, id: subcreddit, subcreddit: data
|
||||
expect(subcreddit.closed_at).to_not eq(nil)
|
||||
end
|
||||
|
||||
expect(response).to redirect_to(subcreddit_url(subcreddit))
|
||||
end
|
||||
it 'should redirect to the subcreddit' do
|
||||
put :update, id: subcreddit, subcreddit: data
|
||||
|
||||
it 'should display a notice flash message' do
|
||||
put :update, id: subcreddit, subcreddit: data
|
||||
expect(response).to redirect_to(subcreddit_url(subcreddit))
|
||||
end
|
||||
|
||||
expect(flash[:notice]).to be_present
|
||||
end
|
||||
end
|
||||
it 'should display a notice flash message' do
|
||||
put :update, id: subcreddit, subcreddit: data
|
||||
|
||||
context 'with invalid data' do
|
||||
before(:each) { data[:closed] = 'bad' }
|
||||
expect(flash[:notice]).to be_present
|
||||
end
|
||||
|
||||
it 'should render :edit' do
|
||||
put :update, id: subcreddit, subcreddit: data
|
||||
context 'with invalid data' do
|
||||
before(:each) { data[:closed] = 'bad' }
|
||||
|
||||
expect(response).to render_template(:edit)
|
||||
it 'should render :edit' do
|
||||
put :update, id: subcreddit, subcreddit: data
|
||||
|
||||
expect(response).to render_template(:edit)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,28 +3,54 @@ require 'rails_helper'
|
|||
describe 'Edit Comment', type: :feature do
|
||||
let!(:user) { create(:user) }
|
||||
let!(:post) { create(:post) }
|
||||
let!(:comment) { create(:comment, post: post, user: user) }
|
||||
|
||||
context 'when signed in' do
|
||||
let(:content) { 'Some different data' }
|
||||
let!(:comment) { create(:comment, post: post, user: user) }
|
||||
|
||||
before(:each) { signin(user: user) }
|
||||
|
||||
context 'with valid data' do
|
||||
before(:each) do
|
||||
context 'when owner' do
|
||||
let(:content) { 'Some different data' }
|
||||
|
||||
context 'with valid data' do
|
||||
before(:each) do
|
||||
visit edit_subcreddit_post_comment_path(post.subcreddit,
|
||||
post,
|
||||
comment)
|
||||
|
||||
fill_in :comment_content, with: content
|
||||
|
||||
click_button 'Update Comment'
|
||||
end
|
||||
|
||||
it 'should notify that the comment was edited' do
|
||||
expect(page).to have_content('updated')
|
||||
end
|
||||
|
||||
it 'should update the comment' do
|
||||
expect(page).to have_content(content)
|
||||
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)
|
||||
|
||||
fill_in :comment_content, with: content
|
||||
|
||||
click_button 'Update Comment'
|
||||
end
|
||||
|
||||
it 'should notify that the comment was edited' do
|
||||
expect(page).to have_content('updated')
|
||||
end
|
||||
|
||||
it 'should update the comment' do
|
||||
expect(page).to have_content(content)
|
||||
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
|
||||
|
|
|
@ -1,33 +1,58 @@
|
|||
require 'rails_helper'
|
||||
|
||||
describe 'Edit Post', type: :feature do
|
||||
let!(:subcreddit) { create(:subcreddit) }
|
||||
|
||||
context 'when signed in' do
|
||||
let!(:user) { create(:user) }
|
||||
let!(:subcreddit) { create(:subcreddit) }
|
||||
let!(:post) { create(:post, subcreddit: subcreddit, user: user) }
|
||||
let(:new_post) { build_stubbed(:post) }
|
||||
|
||||
before(:each) { signin(user: user) }
|
||||
|
||||
context 'with valid data' do
|
||||
before(:each) do
|
||||
context 'when owner' do
|
||||
let!(:post) { create(:post, subcreddit: subcreddit, user: user) }
|
||||
|
||||
context 'with valid data' do
|
||||
before(:each) do
|
||||
visit edit_subcreddit_post_path(subcreddit, post)
|
||||
|
||||
fill_in :post_title, with: new_post.title
|
||||
fill_in :post_link, with: new_post.link
|
||||
fill_in :post_content, with: new_post.content
|
||||
|
||||
click_button 'Update Post'
|
||||
end
|
||||
|
||||
it 'should notify that the post was edited' do
|
||||
expect(page).to have_content('updated')
|
||||
end
|
||||
|
||||
it 'should show the updated post' do
|
||||
expect(page).to have_content(new_post.title)
|
||||
expect(page).to have_content(new_post.content)
|
||||
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)
|
||||
|
||||
fill_in :post_title, with: new_post.title
|
||||
fill_in :post_link, with: new_post.link
|
||||
fill_in :post_content, with: new_post.content
|
||||
|
||||
click_button 'Update Post'
|
||||
end
|
||||
|
||||
it 'should notify that the post was edited' do
|
||||
expect(page).to have_content('updated')
|
||||
end
|
||||
|
||||
it 'should show the updated post' do
|
||||
expect(page).to have_content(new_post.title)
|
||||
expect(page).to have_content(new_post.content)
|
||||
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
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
require 'rails_helper'
|
||||
|
||||
describe 'New Post', type: :feature do
|
||||
let!(:subcreddit) { create(:subcreddit) }
|
||||
|
||||
context 'when signed in' do
|
||||
let!(:user) { create(:user) }
|
||||
let!(:subcreddit) { create(:subcreddit) }
|
||||
let!(:post) { build(:post, subcreddit: subcreddit) }
|
||||
|
||||
before(:each) { signin(user: user) }
|
||||
|
@ -46,4 +47,15 @@ describe 'New Post', type: :feature do
|
|||
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
|
||||
|
|
|
@ -4,36 +4,60 @@ describe 'Edit Subcreddit', type: :feature do
|
|||
before(:each) { signout }
|
||||
|
||||
context 'when logged in' do
|
||||
context 'when board is open' do
|
||||
let!(:subcreddit) { create(:subcreddit) }
|
||||
before(:each) do
|
||||
visit subcreddits_path
|
||||
click_link 'Edit'
|
||||
check :subcreddit_closed
|
||||
click_button 'Update Subcreddit'
|
||||
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
|
||||
before(:each) do
|
||||
visit subcreddits_path
|
||||
click_link 'Edit'
|
||||
check :subcreddit_closed
|
||||
click_button 'Update Subcreddit'
|
||||
end
|
||||
|
||||
it 'should be notified the subcreddit was updated' do
|
||||
expect(page).to have_content('updated')
|
||||
end
|
||||
|
||||
it 'should close the board when closed is checked' do
|
||||
expect(page).to have_content('closed')
|
||||
end
|
||||
end
|
||||
|
||||
it 'should be notified the subcreddit was updated' do
|
||||
expect(page).to have_content('updated')
|
||||
end
|
||||
context 'when board is closed' do
|
||||
let!(:subcreddit) do
|
||||
create(:subcreddit, owner: user, closed_at: Time.now)
|
||||
end
|
||||
|
||||
it 'should close the board when closed is checked' do
|
||||
expect(page).to have_content('closed')
|
||||
before(:each) do
|
||||
visit subcreddits_path
|
||||
click_link 'Edit'
|
||||
uncheck :subcreddit_closed
|
||||
click_button 'Update Subcreddit'
|
||||
end
|
||||
|
||||
it 'should open the board when closed is checked' do
|
||||
expect(page).to_not have_content('closed')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when board is closed' do
|
||||
let!(:subcreddit) { create(:subcreddit, closed_at: Time.now) }
|
||||
before(:each) do
|
||||
context 'when not owner' do
|
||||
let!(:subcreddit) { create(:subcreddit) }
|
||||
|
||||
it 'should not allow editing of subcreddit' do
|
||||
visit subcreddits_path
|
||||
click_link 'Edit'
|
||||
uncheck :subcreddit_closed
|
||||
click_button 'Update Subcreddit'
|
||||
end
|
||||
|
||||
it 'should open the board when closed is checked' do
|
||||
expect(page).to_not have_content('closed')
|
||||
expect(page).to have_content('not authorized')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when not logged in' do
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,7 +4,11 @@ describe 'New Subcreddit', type: :feature do
|
|||
before(:each) { signout }
|
||||
|
||||
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
|
||||
|
||||
context 'when signed in' do
|
||||
|
|
15
spec/policies/application_policy_spec.rb
Normal file
15
spec/policies/application_policy_spec.rb
Normal 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
|
48
spec/policies/comment_policy_spec.rb
Normal file
48
spec/policies/comment_policy_spec.rb
Normal 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
|
48
spec/policies/post_policy_spec.rb
Normal file
48
spec/policies/post_policy_spec.rb
Normal 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
|
49
spec/policies/subcreddit_policy_spec.rb
Normal file
49
spec/policies/subcreddit_policy_spec.rb
Normal 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
|
|
@ -12,11 +12,13 @@ require 'rspec/rails'
|
|||
require 'shoulda/matchers'
|
||||
require 'capybara/rails'
|
||||
require 'capybara/rspec'
|
||||
require 'pundit/rspec'
|
||||
|
||||
require 'support/capybara'
|
||||
require 'support/database_cleaner'
|
||||
require 'support/factory_girl'
|
||||
require 'support/helpers'
|
||||
require 'support/pundit_matcher'
|
||||
|
||||
ActiveRecord::Migration.maintain_test_schema!
|
||||
|
||||
|
|
15
spec/support/pundit_matcher.rb
Normal file
15
spec/support/pundit_matcher.rb
Normal 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
|
Loading…
Reference in a new issue