I am a junior developer working on my first web application for a customer, an electronic commerce portal using Rails 4.2.4, Devise and a pins scaffolding.
Devise is working great and anyone can signup and login and CRUD a pin.
Problem: Users cannot be given access to CUD as the pins contain live customer products that are for sale.
I am therfore trying to implement pundit so that users are purely RESTRICTED to read only and CANNOT create, update or destroy pins, Only the business owner can do so in an Admin capacity.
Currently, I am getting the error "Pundit::NotDefinedError in PinsController#new
1.) How can I add myself as the admin(is this through a migration?) 2) How can I get Pundit working.
class PinsController < ApplicationController
before_action :set_pin, only: [:show, :edit, :update, :destroy]
before_action :correct_user, only: [:edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
def index
if params[:search].present? && !params[:search].nil?
@pins = Pin.where("description LIKE ?", "%#{params[:search]}%").paginate(:page => params[:page], :per_page => 15)
else
@pins = Pin.all.order("created_at DESC").paginate(:page => params[:page], :per_page => 15)
end
end
def show
end
def new
@pin = current_user.pins.build
authorize @pins
end
def edit
end
def create
@pin = current_user.pins.build(pin_params)
if @pin.save
redirect_to @pin, notice: 'Pin was successfully created.'
else
render :new
end
end
def update
if @pin.update(pin_params)
redirect_to @pin, notice: 'Pin was successfully updated.'
else
render :edit
end
end
def destroy
@pin.destroy
redirect_to pins_url
end
private
# Use callbacks to share common setup or constraints between actions.
def set_pin
@pin = Pin.find_by(id: params[:id])
end
def correct_user
@pin = current_user.pins.find_by(id: params[:id])
redirect_to pins_path, notice: "Not authorized to edit this pin" if @pin.nil?
end
# Never trust parameters from the scary internet, only allow the white list through.
def pin_params
params.require(:pin).permit(:description, :image)
end
end
Blockquote
class ApplicationPolicy
attr_reader :user, :pin
def initialize(user, pin)
raise Pundit::NotAuthorizedError, "must be logged in" unless user
@user = user
@pin = pin
end
def index?
true
end
def show?
scope.where(:id => record.id).exists?
end
def create?
user.admin?
end
def new?
user.admin?
end
def update?
user.admin?
end
def edit?
update?
end
def destroy?
user.admin?
end
def scope
Pundit.policy_scope!(user, record.class)
end
class Scope
attr_reader :user, :scope
def initialize(user, scope)
@user = user
@scope = scope
end
def resolve
scope
end
end
end
Blockquote
class ApplicationController < ActionController::Base
include Pundit
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
protect_from_forgery with: :exception
before_filter :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :name
devise_parameter_sanitizer.for(:account_update) << :name
end
private
def user_not_authorized
flash[:warning] = "You are not authorized to perform this action."
redirect_to(request.referrer || root_path)
end
end
Blockquote
class Pin < ActiveRecord::Base
belongs_to :user
has_attached_file :image, :styles => { :medium => "300x300>", :thumb => "100x100>" }
validates_attachment_content_type :image, :content_type => ["image/jpg", "image/jpeg", "image/png"]
validates :image, presence: true
validates :description, presence: true
end
Blockquote
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :pins, dependent: :destroy
validates :name, presence: true
end