Skip to content

Instantly share code, notes, and snippets.

@mattmartini
Created October 6, 2016 17:56
Show Gist options
  • Save mattmartini/45ed2056c5703c0ef6498cfbf6f19714 to your computer and use it in GitHub Desktop.
Save mattmartini/45ed2056c5703c0ef6498cfbf6f19714 to your computer and use it in GitHub Desktop.
# app/models/permissions/admin_permission.rb
module Permissions
class AdminPermission < BasePermission
def initialize(user)
allow_all
end
end
end
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
# include SessionsHelper
before_filter :check_authorization
delegate :allow_action?, to: :current_permission
helper_method :allow_action?
delegate :allow_attribute?, to: :current_permission
helper_method :allow_attribute?
private
def current_permission
@current_permission ||= Permissions.permission_for(current_user)
end
def current_resource
nil
end
def check_authorization
if current_permission.allow_action?(params[:controller], params[:action], current_resource)
current_permission.permit_params! params
else
redirect_to root_url, alert: "Not Authorized."
end
end
def current_user
# @current_user ||= User.find(session[:user_id]) if session[:user_id]
@current_user ||= User.find_by_auth_token(cookies[:auth_token]) if cookies[:auth_token]
end
helper_method :current_user
end
# app/models/permissions/base_permission.rb
module Permissions
class BasePermission
def allow_action?(controller, action, resource = nil)
allowed = @allow_all || @allowed_actions[[controller.to_s, action.to_s]]
allowed && (allowed == true || resource && allowed.call(resource))
end
def allow_all
@allow_all = true
end
def allow_action(controllers, actions, &block)
@allowed_actions ||= {}
Array(controllers).each do |controller|
Array(actions).each do |action|
@allowed_actions[[controller.to_s, action.to_s]] = block || true
end
end
end
def allow_attribute(resources, attributes)
@allowed_params ||= {}
Array(resources).each do |resource|
@allowed_params[resource] ||= []
@allowed_params[resource] += Array(attributes)
end
end
def allow_attribute?(resource, attribute)
if @allow_all
true
elsif @allowed_params && @allowed_params[resource]
@allowed_params[resource].include? attribute
end
end
def permit_params!(params)
if @allow_all
params.permit!
elsif @allowed_params
@allowed_params.each do |resource, attributes|
if params[resource].respond_to? :permit
params[resource] = params[resource].permit(*attributes)
end
end
end
end
end
end
# app/models/permissions/captain_permission.rb
module Permissions
class CaptainPermission < BasePermission
def initialize(user)
allow_action :users, [:new, :create, :edit, :update]
allow_action :sessions, [:new, :create, :destroy]
allow_action :password_resets, [:new, :create, :edit, :update]
allow_action :pages, [:show]
allow_action :ranks, [:index, :show]
allow_action :precepts, [:index, :show]
allow_action :bulletins, [:index, :show, :new, :create, :edit, :update, :destroy]
end
end
end
# app/models/permissions/guest_permission.rb
module Permissions
class GuestPermission < BasePermission
def initialize(user)
allow_action :users, [:new, :create]
allow_action :sessions, [:new, :create, :destroy]
allow_action :password_resets, [:new, :create, :edit, :update]
allow_action :pages, [:show]
allow_action :ranks, [:index, :show]
allow_action :precepts, [:index, :show]
allow_action :bulletins, [:index, :show]
end
end
end
# app/models/permissions.rb
module Permissions
def self.permission_for(user)
if user.nil?
VisitorPermission.new
elsif user.roles.include? "admin"
AdminPermisson.new(user)
elsif user.roles.include? "captain"
CaptainPermission.new(user)
elsif user.roles.include? "student"
StudentPermission.new(user)
# elsif user.roles.include? "guest"
else
GuestPermission.new(user)
end
end
end
# app/controllers/ranks_controller.rb
class RanksController < ApplicationController
# before_action :set_rank, only: [:show, :edit, :update, :destroy]
# GET /ranks
# GET /ranks.json
def index
@ranks = Rank.all
end
# GET /ranks/1
# GET /ranks/1.json
def show
@rank = current_resource
end
# GET /ranks/new
def new
@rank = Rank.new
end
# GET /ranks/1/edit
def edit
@rank = current_resource
end
# POST /ranks
# POST /ranks.json
def create
@rank = Rank.new(rank_params)
respond_to do |format|
if @rank.save
format.html { redirect_to @rank, notice: 'Rank was successfully created.' }
format.json { render :show, status: :created, location: @rank }
else
format.html { render :new }
format.json { render json: @rank.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /ranks/1
# PATCH/PUT /ranks/1.json
def update
@rank = current_resource
respond_to do |format|
if @rank.update(rank_params)
format.html { redirect_to @rank, notice: 'Rank was successfully updated.' }
format.json { render :show, status: :ok, location: @rank }
else
format.html { render :edit }
format.json { render json: @rank.errors, status: :unprocessable_entity }
end
end
end
# DELETE /ranks/1
# DELETE /ranks/1.json
def destroy
@rank = current_resource
@rank.destroy
respond_to do |format|
format.html { redirect_to ranks_url, notice: 'Rank was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_rank
@rank = Rank.find(params[:id])
end
def current_resource
@current_resource ||= Rank.find(params[:id]) if params[:id]
end
# Never trust parameters from the scary internet, only allow the white list through.
def rank_params
params.require(:rank).permit(:name, :belt, :traditional)
end
end
# spec/controllers/ranks_controller_spec.rb
require 'rails_helper'
# This spec was generated by rspec-rails when you ran the scaffold generator.
# It demonstrates how one might use RSpec to specify the controller code that
# was generated by Rails when you ran the scaffold generator.
#
# It assumes that the implementation code is generated by the rails scaffold
# generator. If you are using any extension libraries to generate different
# controller code, this generated spec may or may not pass.
#
# It only uses APIs available in rails and/or rspec-rails. There are a number
# of tools you can use to make these specs even more expressive, but we're
# sticking to rails and rspec-rails APIs to keep things simple and stable.
#
# Compared to earlier versions of this generator, there is very limited use of
# stubs and message expectations in this spec. Stubs are only used when there
# is no simpler way to get a handle on the object needed for the example.
# Message expectations are only used when there is no simpler way to specify
# that an instance is receiving a specific message.
RSpec.describe RanksController, type: :controller do
it { should be_a ApplicationController }
# it "should have a current_user" do
# login_admin
# expect(subject.current_user).to_not eq(nil)
# end
#
# it "should get index" do
# login_admin
# get 'index'
# expect(response).to be_success
# end
let(:admin_user) { create(:admin) }
# let(:user) { create(:user) }
# This should return the minimal set of attributes required to create a valid
# Rank. As you add validations to Rank, be sure to
# adjust the attributes here as well.
let(:valid_attributes) {
{
:name => "aShodan",
:belt => "Black Belt",
:traditional => 'Black Belt'
}
}
let(:invalid_attributes) {
{
:name => nil,
:belt => "Black Belt",
:traditional => 'Black Belt'
}
}
# This should return the minimal set of values that should be in the session
# in order to pass any filters (e.g. authentication) defined in
# RanksController. Be sure to keep this updated too.
let(:valid_session) { { cookies[:auth_token] => admin_user.auth_token } }
describe "GET #index" do
it "assigns all ranks as @ranks" do
rank = Rank.create! valid_attributes
get :index, {}, valid_session
expect(assigns(:ranks)).to eq([rank])
end
end
describe "GET #show" do
it "assigns the requested rank as @rank" do
rank = Rank.create! valid_attributes
get :show, {:id => rank.to_param}, valid_session
expect(assigns(:rank)).to eq(rank)
end
end
describe "GET #new" do
it "assigns a new rank as @rank" do
get :new, {}
expect(assigns(:rank)).to be_a_new(Rank)
end
end
describe "GET #edit" do
it "assigns the requested rank as @rank" do
rank = Rank.create! valid_attributes
get :edit, {:id => rank.to_param}, valid_session
expect(assigns(:rank)).to eq(rank)
end
end
describe "POST #create" do
context "with valid params" do
it "creates a new Rank" do
expect {
post :create, {:rank => valid_attributes}, valid_session
}.to change(Rank, :count).by(1)
end
it "assigns a newly created rank as @rank" do
post :create, {:rank => valid_attributes}, valid_session
expect(assigns(:rank)).to be_a(Rank)
expect(assigns(:rank)).to be_persisted
end
it "redirects to the created rank" do
post :create, {:rank => valid_attributes}, valid_session
expect(response).to redirect_to(Rank.last)
end
end
context "with invalid params" do
it "assigns a newly created but unsaved rank as @rank" do
post :create, {:rank => invalid_attributes}, valid_session
expect(assigns(:rank)).to be_a_new(Rank)
end
it "re-renders the 'new' template" do
post :create, {:rank => invalid_attributes}, valid_session
expect(response).to render_template("new")
end
end
end
describe "PUT #update" do
context "with valid params" do
let(:new_attributes) {
{
:name => "aSho Kyu",
:belt => "Brown Belt II",
:traditional => 'Brown Belt III'
}
# skip("Add a hash of attributes valid for your model")
}
it "updates the requested rank" do
rank = Rank.create! valid_attributes
put :update, {:id => rank.to_param, :rank => new_attributes}, valid_session
rank.reload
expect(rank.name).to eq('aSho Kyu')
expect(rank.belt).to eq('Brown Belt II')
expect(rank.traditional).to eq('Brown Belt III')
expect(rank.full_rank).to eq('aSho Kyu - Brown Belt II')
expect(rank.traditional_rank).to eq('aSho Kyu - Brown Belt III')
# skip("Add assertions for updated state")
end
it "assigns the requested rank as @rank" do
rank = Rank.create! valid_attributes
put :update, {:id => rank.to_param, :rank => valid_attributes}, valid_session
expect(assigns(:rank)).to eq(rank)
end
it "redirects to the rank" do
rank = Rank.create! valid_attributes
put :update, {:id => rank.to_param, :rank => valid_attributes}, valid_session
expect(response).to redirect_to(rank)
end
end
context "with invalid params" do
it "assigns the rank as @rank" do
rank = Rank.create! valid_attributes
put :update, {:id => rank.to_param, :rank => invalid_attributes}, valid_session
expect(assigns(:rank)).to eq(rank)
end
it "re-renders the 'edit' template" do
rank = Rank.create! valid_attributes
put :update, {:id => rank.to_param, :rank => invalid_attributes}, valid_session
expect(response).to render_template("edit")
end
end
end
describe "DELETE #destroy" do
it "destroys the requested rank" do
rank = Rank.create! valid_attributes
expect {
delete :destroy, {:id => rank.to_param}, valid_session
}.to change(Rank, :count).by(-1)
end
it "redirects to the ranks list" do
rank = Rank.create! valid_attributes
delete :destroy, {:id => rank.to_param}, valid_session
expect(response).to redirect_to(ranks_url)
end
end
end
# app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by_email(params[:email])
if user && user.authenticate(params[:password])
# session[:user_id] = user.id
if params[:remember_me]
cookies.permanent[:auth_token] = user.auth_token
else
cookies[:auth_token] = user.auth_token
end
redirect_to root_url, notice: "Logged in!"
else
flash.now.alert = "Email or password is invalid"
render "new"
end
end
def destroy
# session[:user_id] = nil
cookies.delete(:auth_token)
redirect_to root_url, notice: "Logged out!"
end
end
# app/models/permissions/student_permission.rb
module Permissions
class StudentPermission < BasePermission
def initialize(user)
allow_action :users, [:new, :create]
allow_action :sessions, [:new, :create, :destroy]
allow_action :password_resets, [:new, :create, :edit, :update]
allow_action :pages, [:show]
allow_action :ranks, [:index, :show]
allow_action :precepts, [:index, :show]
allow_action :bulletins, [:index, :show]
end
end
end
# app/controllers/users_controller.rb
class UsersController < ApplicationController
def new
@user = User.new
end
def create
@user = User.new(user_params)
if @user.save
# session[:user_id] = @user.id
cookies[:auth_token] = @user.auth_token
redirect_to root_url, notice: "Thank you for signing up!"
else
render "new"
end
end
def edit
@user = current_user
end
def update
@user = current_user
if @user.update_attributes(user_params)
redirect_to root_url, notice: "Updated profile."
else
render "new"
end
end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation, :roles_mask, :roles)
end
end
# app/models/permissions/visitor_permission.rb
module Permissions
class VisitorPermission < BasePermission
def initialize
allow_action :users, [:new, :create]
allow_action :sessions, [:new, :create, :destroy]
allow_action :password_resets, [:new, :create, :edit, :update]
allow_action :pages, [:show]
allow_action :ranks, [:index, :show]
allow_action :precepts, [:index, :show]
allow_action :bulletins, [:index, :show]
end
end
end
@kul1
Copy link

kul1 commented Feb 23, 2018

Did your code fixed to work OK or just code to ask question

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment