Merge pull request #116 from AyuntamientoMadrid/admin-77
Administrator and Moderator basic interface
This commit is contained in:
1
Gemfile
1
Gemfile
@@ -28,6 +28,7 @@ gem 'foundation-rails'
|
||||
gem 'acts_as_votable'
|
||||
gem "recaptcha", require: "recaptcha/rails"
|
||||
gem 'ckeditor'
|
||||
gem 'cancancan'
|
||||
|
||||
group :development, :test do
|
||||
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
|
||||
|
||||
@@ -53,6 +53,7 @@ GEM
|
||||
builder (3.2.2)
|
||||
byebug (5.0.0)
|
||||
columnize (= 0.9.0)
|
||||
cancancan (1.12.0)
|
||||
capistrano (3.4.0)
|
||||
i18n
|
||||
rake (>= 10.0.0)
|
||||
@@ -290,6 +291,7 @@ DEPENDENCIES
|
||||
acts_as_commentable_with_threading
|
||||
acts_as_votable
|
||||
byebug
|
||||
cancancan
|
||||
capistrano (= 3.4.0)
|
||||
capistrano-bundler (= 1.1.4)
|
||||
capistrano-passenger
|
||||
|
||||
@@ -2,6 +2,7 @@ class AccountController < ApplicationController
|
||||
|
||||
before_action :authenticate_user!
|
||||
before_action :set_account
|
||||
load_and_authorize_resource class: "User"
|
||||
|
||||
def show
|
||||
end
|
||||
|
||||
13
app/controllers/admin/base_controller.rb
Normal file
13
app/controllers/admin/base_controller.rb
Normal file
@@ -0,0 +1,13 @@
|
||||
class Admin::BaseController < ApplicationController
|
||||
before_action :authenticate_user!
|
||||
|
||||
skip_authorization_check
|
||||
before_action :verify_administrator
|
||||
|
||||
private
|
||||
|
||||
def verify_administrator
|
||||
raise CanCan::AccessDenied unless current_user.try(:administrator?)
|
||||
end
|
||||
|
||||
end
|
||||
6
app/controllers/admin/dashboard_controller.rb
Normal file
6
app/controllers/admin/dashboard_controller.rb
Normal file
@@ -0,0 +1,6 @@
|
||||
class Admin::DashboardController < Admin::BaseController
|
||||
|
||||
def index
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,6 +1,9 @@
|
||||
require "application_responder"
|
||||
|
||||
class ApplicationController < ActionController::Base
|
||||
|
||||
check_authorization unless: :devise_controller?
|
||||
|
||||
self.responder = ApplicationResponder
|
||||
respond_to :html
|
||||
|
||||
@@ -11,6 +14,10 @@ class ApplicationController < ActionController::Base
|
||||
# For APIs, you may want to use :null_session instead.
|
||||
protect_from_forgery with: :exception
|
||||
|
||||
rescue_from CanCan::AccessDenied do |exception|
|
||||
redirect_to main_app.root_url, alert: exception.message
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_locale
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
class CommentsController < ApplicationController
|
||||
before_action :authenticate_user!
|
||||
before_action :set_debate, :set_parent, only: :create
|
||||
before_action :build_comment, only: :create
|
||||
load_and_authorize_resource
|
||||
respond_to :html, :js
|
||||
|
||||
def create
|
||||
@comment = Comment.build(@debate, current_user, params[:comment][:body])
|
||||
@comment.save!
|
||||
@comment.move_to_child_of(@parent) if reply?
|
||||
@comment.move_to_child_of(parent) if reply?
|
||||
|
||||
Mailer.comment(@comment).deliver_now if email_on_debate_comment?
|
||||
Mailer.reply(@comment).deliver_now if email_on_comment_reply?
|
||||
@@ -15,7 +15,6 @@ class CommentsController < ApplicationController
|
||||
end
|
||||
|
||||
def vote
|
||||
@comment = Comment.find(params[:id])
|
||||
@comment.vote_by(voter: current_user, vote: params[:value])
|
||||
respond_with @comment
|
||||
end
|
||||
@@ -25,16 +24,20 @@ class CommentsController < ApplicationController
|
||||
params.require(:comments).permit(:commentable_type, :commentable_id, :body)
|
||||
end
|
||||
|
||||
def set_debate
|
||||
@debate = Debate.find(params[:debate_id])
|
||||
def build_comment
|
||||
@comment = Comment.build(debate, current_user, params[:comment][:body])
|
||||
end
|
||||
|
||||
def set_parent
|
||||
@parent = Comment.find_parent(params[:comment])
|
||||
def debate
|
||||
@debate ||= Debate.find(params[:debate_id])
|
||||
end
|
||||
|
||||
def parent
|
||||
@parent ||= Comment.find_parent(params[:comment])
|
||||
end
|
||||
|
||||
def reply?
|
||||
@parent.class == Comment
|
||||
parent.class == Comment
|
||||
end
|
||||
|
||||
def email_on_debate_comment?
|
||||
@@ -42,6 +45,6 @@ class CommentsController < ApplicationController
|
||||
end
|
||||
|
||||
def email_on_comment_reply?
|
||||
reply? && @parent.author.email_on_comment_reply?
|
||||
reply? && parent.author.email_on_comment_reply?
|
||||
end
|
||||
end
|
||||
@@ -1,8 +1,7 @@
|
||||
class DebatesController < ApplicationController
|
||||
include RecaptchaHelper
|
||||
before_action :set_debate, only: [:show, :edit, :update, :vote]
|
||||
before_action :authenticate_user!, except: [:index, :show]
|
||||
before_action :validate_ownership, only: [:edit, :update]
|
||||
load_and_authorize_resource
|
||||
|
||||
def index
|
||||
if params[:tag]
|
||||
@@ -56,10 +55,6 @@ class DebatesController < ApplicationController
|
||||
params.require(:debate).permit(:title, :description, :tag_list, :terms_of_service)
|
||||
end
|
||||
|
||||
def validate_ownership
|
||||
raise ActiveRecord::RecordNotFound unless @debate.editable_by?(current_user)
|
||||
end
|
||||
|
||||
def set_voted_values(debates_ids)
|
||||
@voted_values = current_user ? current_user.votes_on_debates(debates_ids) : {}
|
||||
end
|
||||
|
||||
13
app/controllers/moderation/base_controller.rb
Normal file
13
app/controllers/moderation/base_controller.rb
Normal file
@@ -0,0 +1,13 @@
|
||||
class Moderation::BaseController < ApplicationController
|
||||
before_action :authenticate_user!
|
||||
|
||||
skip_authorization_check
|
||||
before_action :verify_moderator
|
||||
|
||||
private
|
||||
|
||||
def verify_moderator
|
||||
raise CanCan::AccessDenied unless current_user.try(:moderator?) || current_user.try(:administrator?)
|
||||
end
|
||||
|
||||
end
|
||||
6
app/controllers/moderation/dashboard_controller.rb
Normal file
6
app/controllers/moderation/dashboard_controller.rb
Normal file
@@ -0,0 +1,6 @@
|
||||
class Moderation::DashboardController < Moderation::BaseController
|
||||
|
||||
def index
|
||||
end
|
||||
|
||||
end
|
||||
26
app/models/ability.rb
Normal file
26
app/models/ability.rb
Normal file
@@ -0,0 +1,26 @@
|
||||
class Ability
|
||||
include CanCan::Ability
|
||||
|
||||
def initialize(user)
|
||||
# Not logged in users
|
||||
can :read, Debate
|
||||
|
||||
if user # logged-in users
|
||||
can [:read, :update], User, id: user.id
|
||||
|
||||
can [:read, :create, :vote], Debate
|
||||
can :update, Debate do |debate|
|
||||
debate.editable_by?(user)
|
||||
end
|
||||
|
||||
can [:create, :vote], Comment
|
||||
|
||||
if user.moderator? or user.administrator?
|
||||
|
||||
elsif user.administrator?
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
6
app/models/administrator.rb
Normal file
6
app/models/administrator.rb
Normal file
@@ -0,0 +1,6 @@
|
||||
class Administrator < ActiveRecord::Base
|
||||
belongs_to :user
|
||||
delegate :name, :email, to: :user
|
||||
|
||||
validates :user_id, presence: true, uniqueness: true
|
||||
end
|
||||
6
app/models/moderator.rb
Normal file
6
app/models/moderator.rb
Normal file
@@ -0,0 +1,6 @@
|
||||
class Moderator < ActiveRecord::Base
|
||||
belongs_to :user
|
||||
delegate :name, :email, to: :user
|
||||
|
||||
validates :user_id, presence: true, uniqueness: true
|
||||
end
|
||||
@@ -19,4 +19,12 @@ class User < ActiveRecord::Base
|
||||
voted = votes.where("votable_type = ? AND votable_id IN (?)", "Debate", debates_ids)
|
||||
voted.each_with_object({}){ |v,_| _[v.votable_id] = v.vote_flag }
|
||||
end
|
||||
|
||||
def administrator?
|
||||
@is_administrator ||= Administrator.where(user_id: id).exists?
|
||||
end
|
||||
|
||||
def moderator?
|
||||
@is_moderator ||= Moderator.where(user_id: id).exists?
|
||||
end
|
||||
end
|
||||
|
||||
1
app/views/admin/dashboard/index.html.erb
Normal file
1
app/views/admin/dashboard/index.html.erb
Normal file
@@ -0,0 +1 @@
|
||||
<h1><%= t("admin.dashboard.index.title") %></h1>
|
||||
1
app/views/moderation/dashboard/index.html.erb
Normal file
1
app/views/moderation/dashboard/index.html.erb
Normal file
@@ -0,0 +1 @@
|
||||
<h1><%= t("moderation.dashboard.index.title") %></h1>
|
||||
@@ -85,6 +85,8 @@ search:
|
||||
# ignore_missing:
|
||||
# - 'errors.messages.{accepted,blank,invalid,too_short,too_long}'
|
||||
# - '{devise,simple_form}.*'
|
||||
ignore_missing:
|
||||
- 'unauthorized.*'
|
||||
|
||||
## Consider these keys used:
|
||||
ignore_unused:
|
||||
@@ -93,6 +95,8 @@ ignore_unused:
|
||||
# - 'simple_form.{yes,no}'
|
||||
# - 'simple_form.{placeholders,hints,labels}.*'
|
||||
# - 'simple_form.{error_notification,required}.:'
|
||||
ignore_unused:
|
||||
- 'unauthorized.*'
|
||||
|
||||
## Exclude these keys from the `i18n-tasks eq-base' report:
|
||||
# ignore_eq_base:
|
||||
|
||||
@@ -12,6 +12,14 @@ en:
|
||||
create_debate: Create a debate
|
||||
my_account_link: My account
|
||||
language: Site language
|
||||
admin:
|
||||
dashboard:
|
||||
index:
|
||||
title: Administration
|
||||
moderation:
|
||||
dashboard:
|
||||
index:
|
||||
title: Moderation
|
||||
debates:
|
||||
index:
|
||||
create_debate: Create a debate
|
||||
@@ -81,3 +89,7 @@ en:
|
||||
subject: Someone has commented on your debate
|
||||
reply:
|
||||
subject: Someone has replied to your comment
|
||||
unauthorized:
|
||||
default: "You are not authorized to access this page."
|
||||
manage:
|
||||
all: "You are not authorized to %{action} %{subject}."
|
||||
|
||||
@@ -12,6 +12,14 @@ es:
|
||||
create_debate: Crea un debate
|
||||
my_account_link: Mi cuenta
|
||||
language: Idioma de la página
|
||||
admin:
|
||||
dashboard:
|
||||
index:
|
||||
title: Administración
|
||||
moderation:
|
||||
dashboard:
|
||||
index:
|
||||
title: Moderación
|
||||
debates:
|
||||
index:
|
||||
create_debate: Crea un debate
|
||||
@@ -81,3 +89,21 @@ es:
|
||||
subject: Alguien ha comentado en tu debate
|
||||
reply:
|
||||
subject: Alguien ha respondido a tu comentario
|
||||
unauthorized:
|
||||
default: "No tienes permiso para acceder a esta página."
|
||||
index:
|
||||
all: "No tienes permiso para listar %{subject}"
|
||||
show:
|
||||
all: "No tienes permiso para ver %{subject}"
|
||||
edit:
|
||||
all: "No tienes permiso para editar %{subject}"
|
||||
update:
|
||||
all: "No tienes permiso para modificar %{subject}"
|
||||
create:
|
||||
all: "No tienes permiso para crear %{subject}"
|
||||
delete:
|
||||
all: "No tienes permiso para borrar %{subject}"
|
||||
manage:
|
||||
all: "No tienes permiso para realizar la acción '%{action}' sobre %{subject}."
|
||||
|
||||
|
||||
|
||||
@@ -17,11 +17,18 @@ Rails.application.routes.draw do
|
||||
post :vote
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
resource :account, controller: "account", only: [:show, :update]
|
||||
|
||||
namespace :admin do
|
||||
root to: "dashboard#index"
|
||||
end
|
||||
|
||||
namespace :moderation do
|
||||
root to: "dashboard#index"
|
||||
end
|
||||
|
||||
# Example of regular route:
|
||||
# get 'products/:id' => 'catalog#view'
|
||||
|
||||
|
||||
7
db/migrate/20150807140235_create_administrators.rb
Normal file
7
db/migrate/20150807140235_create_administrators.rb
Normal file
@@ -0,0 +1,7 @@
|
||||
class CreateAdministrators < ActiveRecord::Migration
|
||||
def change
|
||||
create_table :administrators do |t|
|
||||
t.belongs_to :user, index: true, foreign_key: true
|
||||
end
|
||||
end
|
||||
end
|
||||
7
db/migrate/20150807140346_create_moderators.rb
Normal file
7
db/migrate/20150807140346_create_moderators.rb
Normal file
@@ -0,0 +1,7 @@
|
||||
class CreateModerators < ActiveRecord::Migration
|
||||
def change
|
||||
create_table :moderators do |t|
|
||||
t.belongs_to :user, index: true, foreign_key: true
|
||||
end
|
||||
end
|
||||
end
|
||||
16
db/schema.rb
16
db/schema.rb
@@ -11,11 +11,17 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20150806163142) do
|
||||
ActiveRecord::Schema.define(version: 20150807140346) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
||||
create_table "administrators", force: :cascade do |t|
|
||||
t.integer "user_id"
|
||||
end
|
||||
|
||||
add_index "administrators", ["user_id"], name: "index_administrators_on_user_id", using: :btree
|
||||
|
||||
create_table "comments", force: :cascade do |t|
|
||||
t.integer "commentable_id"
|
||||
t.string "commentable_type"
|
||||
@@ -41,6 +47,12 @@ ActiveRecord::Schema.define(version: 20150806163142) do
|
||||
t.datetime "updated_at", null: false
|
||||
end
|
||||
|
||||
create_table "moderators", force: :cascade do |t|
|
||||
t.integer "user_id"
|
||||
end
|
||||
|
||||
add_index "moderators", ["user_id"], name: "index_moderators_on_user_id", using: :btree
|
||||
|
||||
create_table "taggings", force: :cascade do |t|
|
||||
t.integer "tag_id"
|
||||
t.integer "taggable_id"
|
||||
@@ -105,4 +117,6 @@ ActiveRecord::Schema.define(version: 20150806163142) do
|
||||
add_index "votes", ["votable_id", "votable_type", "vote_scope"], name: "index_votes_on_votable_id_and_votable_type_and_vote_scope", using: :btree
|
||||
add_index "votes", ["voter_id", "voter_type", "vote_scope"], name: "index_votes_on_voter_id_and_voter_type_and_vote_scope", using: :btree
|
||||
|
||||
add_foreign_key "administrators", "users"
|
||||
add_foreign_key "moderators", "users"
|
||||
end
|
||||
|
||||
@@ -31,4 +31,12 @@ FactoryGirl.define do
|
||||
debate
|
||||
end
|
||||
|
||||
factory :administrator do
|
||||
user
|
||||
end
|
||||
|
||||
factory :moderator do
|
||||
user
|
||||
end
|
||||
|
||||
end
|
||||
@@ -10,6 +10,7 @@ feature 'Account' do
|
||||
login_as(@user)
|
||||
visit root_path
|
||||
click_link "My account"
|
||||
expect(current_path).to eq(account_path)
|
||||
|
||||
expect(page).to have_selector("input[value='Manuela']")
|
||||
expect(page).to have_selector("input[value='Colau']")
|
||||
|
||||
34
spec/features/admin_spec.rb
Normal file
34
spec/features/admin_spec.rb
Normal file
@@ -0,0 +1,34 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature 'Admin' do
|
||||
let(:user) { create(:user) }
|
||||
|
||||
scenario 'Access as regular user is not authorized' do
|
||||
login_as(user)
|
||||
visit admin_root_path
|
||||
|
||||
expect(current_path).to eq(root_path)
|
||||
expect(page).to have_content "not authorized"
|
||||
end
|
||||
|
||||
scenario 'Access as a moderator is not authorized' do
|
||||
create(:moderator, user: user)
|
||||
|
||||
login_as(user)
|
||||
visit admin_root_path
|
||||
|
||||
expect(current_path).to eq(root_path)
|
||||
expect(page).to have_content "not authorized"
|
||||
end
|
||||
|
||||
scenario 'Access as an administrator is authorized' do
|
||||
create(:administrator, user: user)
|
||||
|
||||
login_as(user)
|
||||
visit admin_root_path
|
||||
|
||||
expect(current_path).to eq(admin_root_path)
|
||||
expect(page).to_not have_content "not authorized"
|
||||
end
|
||||
|
||||
end
|
||||
@@ -98,9 +98,9 @@ feature 'Debates' do
|
||||
expect(debate).to be_editable
|
||||
login_as(create(:user))
|
||||
|
||||
expect {
|
||||
visit edit_debate_path(debate)
|
||||
}.to raise_error ActiveRecord::RecordNotFound
|
||||
expect(current_path).to eq(root_path)
|
||||
expect(page).to have_content 'not authorized'
|
||||
end
|
||||
|
||||
scenario 'Update should not be posible if debate is not editable' do
|
||||
@@ -109,17 +109,19 @@ feature 'Debates' do
|
||||
expect(debate).to_not be_editable
|
||||
login_as(debate.author)
|
||||
|
||||
expect {
|
||||
visit edit_debate_path(debate)
|
||||
}.to raise_error ActiveRecord::RecordNotFound
|
||||
edit_debate_path(debate)
|
||||
expect(current_path).to eq(root_path)
|
||||
expect(page).to have_content 'not authorized'
|
||||
end
|
||||
|
||||
scenario 'Update should be posible for the author of an editable debate' do
|
||||
debate = create(:debate)
|
||||
login_as(debate.author)
|
||||
|
||||
visit debate_path(debate)
|
||||
click_link 'Edit'
|
||||
visit edit_debate_path(debate)
|
||||
expect(current_path).to eq(edit_debate_path(debate))
|
||||
|
||||
fill_in 'debate_title', with: "End child poverty"
|
||||
fill_in 'debate_description', with: "Let's..."
|
||||
|
||||
|
||||
34
spec/features/moderation_spec.rb
Normal file
34
spec/features/moderation_spec.rb
Normal file
@@ -0,0 +1,34 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature 'Admin' do
|
||||
let(:user) { create(:user) }
|
||||
|
||||
scenario 'Access as regular user is not authorized' do
|
||||
login_as(user)
|
||||
visit moderation_root_path
|
||||
|
||||
expect(current_path).to eq(root_path)
|
||||
expect(page).to have_content "not authorized"
|
||||
end
|
||||
|
||||
scenario 'Access as a moderator is authorized' do
|
||||
create(:moderator, user: user)
|
||||
|
||||
login_as(user)
|
||||
visit moderation_root_path
|
||||
|
||||
expect(current_path).to eq(moderation_root_path)
|
||||
expect(page).to_not have_content "not authorized"
|
||||
end
|
||||
|
||||
scenario 'Access as an administrator is authorized' do
|
||||
create(:administrator, user: user)
|
||||
|
||||
login_as(user)
|
||||
visit moderation_root_path
|
||||
|
||||
expect(current_path).to eq(moderation_root_path)
|
||||
expect(page).to_not have_content "not authorized"
|
||||
end
|
||||
|
||||
end
|
||||
67
spec/models/ability_spec.rb
Normal file
67
spec/models/ability_spec.rb
Normal file
@@ -0,0 +1,67 @@
|
||||
require 'rails_helper'
|
||||
require 'cancan/matchers'
|
||||
|
||||
describe Ability do
|
||||
subject(:ability) { Ability.new(user) }
|
||||
let(:debate) { Debate.new }
|
||||
|
||||
describe "Non-logged in user" do
|
||||
let(:user) { nil }
|
||||
|
||||
it { should be_able_to(:index, Debate) }
|
||||
it { should be_able_to(:show, debate) }
|
||||
it { should_not be_able_to(:edit, Debate) }
|
||||
it { should_not be_able_to(:vote, Debate) }
|
||||
end
|
||||
|
||||
describe "Citizen" do
|
||||
let(:user) { create(:user) }
|
||||
|
||||
it { should be_able_to(:index, Debate) }
|
||||
it { should be_able_to(:show, debate) }
|
||||
it { should be_able_to(:vote, debate) }
|
||||
|
||||
it { should be_able_to(:show, user) }
|
||||
it { should be_able_to(:edit, user) }
|
||||
|
||||
it { should be_able_to(:create, Comment) }
|
||||
it { should be_able_to(:vote, Comment) }
|
||||
|
||||
describe "other users" do
|
||||
let(:other_user) { create(:user) }
|
||||
it { should_not be_able_to(:show, other_user) }
|
||||
it { should_not be_able_to(:edit, other_user) }
|
||||
end
|
||||
|
||||
describe "editing debates" do
|
||||
let(:own_debate) { create(:debate, author: user) }
|
||||
let(:own_debate_non_editable) { create(:debate, author: user) }
|
||||
|
||||
before { allow(own_debate_non_editable).to receive(:editable?).and_return(false) }
|
||||
|
||||
it { should be_able_to(:edit, own_debate) }
|
||||
it { should_not be_able_to(:edit, debate) } # Not his
|
||||
it { should_not be_able_to(:edit, own_debate_non_editable) }
|
||||
end
|
||||
end
|
||||
|
||||
describe "Moderator" do
|
||||
let(:user) { create(:user) }
|
||||
before { create(:moderator, user: user) }
|
||||
|
||||
it { should be_able_to(:index, Debate) }
|
||||
it { should be_able_to(:show, debate) }
|
||||
it { should be_able_to(:vote, debate) }
|
||||
|
||||
end
|
||||
|
||||
describe "Administrator" do
|
||||
let(:user) { create(:user) }
|
||||
before { create(:administrator, user: user) }
|
||||
|
||||
it { should be_able_to(:index, Debate) }
|
||||
it { should be_able_to(:show, debate) }
|
||||
it { should be_able_to(:vote, debate) }
|
||||
|
||||
end
|
||||
end
|
||||
@@ -7,13 +7,13 @@ describe User do
|
||||
@user = create(:user)
|
||||
end
|
||||
|
||||
it "should return {} if no debate" do
|
||||
it "returns {} if no debate" do
|
||||
expect(@user.votes_on_debates()).to eq({})
|
||||
expect(@user.votes_on_debates([])).to eq({})
|
||||
expect(@user.votes_on_debates([nil, nil])).to eq({})
|
||||
end
|
||||
|
||||
it "should return a hash of debates ids and votes" do
|
||||
it "returns a hash of debates ids and votes" do
|
||||
debate1 = create(:debate)
|
||||
debate2 = create(:debate)
|
||||
debate3 = create(:debate)
|
||||
@@ -87,4 +87,28 @@ describe User do
|
||||
end
|
||||
end
|
||||
|
||||
describe "administrator?" do
|
||||
it "is false when the user is not an admin" do
|
||||
expect(subject.administrator?).to be false
|
||||
end
|
||||
|
||||
it "is true when the user is an admin" do
|
||||
subject.save
|
||||
create(:administrator, user: subject)
|
||||
expect(subject.administrator?).to be true
|
||||
end
|
||||
end
|
||||
|
||||
describe "moderator?" do
|
||||
it "is false when the user is not a moderator" do
|
||||
expect(subject.moderator?).to be false
|
||||
end
|
||||
|
||||
it "is true when the user is a moderator" do
|
||||
subject.save
|
||||
create(:moderator, user: subject)
|
||||
expect(subject.moderator?).to be true
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user