Rails 4: "Pundit::NotAuthorizedError"
Rails 4: "Pundit::NotAuthorizedError"
在我的Rails4个应用中,有5个模型:
class User < ActiveRecord::Base
has_many :administrations
has_many :calendars, through: :administrations
end
class Calendar < ActiveRecord::Base
has_many :administrations
has_many :users, through: :administrations
has_many :posts
end
class Administration < ActiveRecord::Base
belongs_to :user
belongs_to :calendar
end
class Post < ActiveRecord::Base
belongs_to :calendar
end
class Comment < ActiveRecord::Base
belongs_to :post
belongs_to :user
end
我使用 Devise 实现了身份验证(因此我们可以访问 current_user
)。
现在,我正在尝试使用 Pundit(第一个定时器)实现授权。
在 documentation 之后,我安装了 gem 和 运行 rails g pundit:install
生成器。
然后,我创建了一个CalendarPolicy
,如下:
class CalendarPolicy < ApplicationPolicy
attr_reader :user, :calendar
def initialize(user, calendar)
@user = user
@calendar = calendar
end
def index?
user.owner? || user.editor? || user.viewer?
end
def show?
user.owner? || user.editor? || user.viewer?
end
def update?
user.owner? || user.editor?
end
def edit?
user.owner? || user.editor?
end
def destroy?
user.owner?
end
end
我还使用以下方法更新了我的 User
模型:
def owner?
Administration.find_by(user_id: params[:user_id], calendar_id: params[:calendar_id]).role == "Owner"
end
def editor?
Administration.find_by(user_id: params[:user_id], calendar_id: params[:calendar_id]).role == "Editor"
end
def viewer?
Administration.find_by(user_id: params[:user_id], calendar_id: params[:calendar_id]).role == "Viewer"
end
我用 authorize @calendar
更新了我的 CalendarsController
操作,如下:
def index
@user = current_user
@calendars = @user.calendars.all
end
# GET /calendars/1
# GET /calendars/1.json
def show
@user = current_user
@calendar = @user.calendars.find(params[:id])
authorize @calendar
end
# GET /calendars/new
def new
@user = current_user
@calendar = @user.calendars.new
authorize @calendar
end
# GET /calendars/1/edit
def edit
@user = current_user
authorize @calendar
end
# POST /calendars
# POST /calendars.json
def create
@user = current_user
@calendar = @user.calendars.create(calendar_params)
authorize @calendar
respond_to do |format|
if @calendar.save
current_user.set_default_role(@calendar.id, 'Owner')
format.html { redirect_to calendar_path(@calendar), notice: 'Calendar was successfully created.' }
format.json { render :show, status: :created, location: @calendar }
else
format.html { render :new }
format.json { render json: @calendar.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /calendars/1
# PATCH/PUT /calendars/1.json
def update
@user = current_user
@calendar = Calendar.find(params[:id])
authorize @calendar
respond_to do |format|
if @calendar.update(calendar_params)
format.html { redirect_to calendar_path(@calendar), notice: 'Calendar was successfully updated.' }
format.json { render :show, status: :ok, location: @calendar }
else
format.html { render :edit }
format.json { render json: @calendar.errors, status: :unprocessable_entity }
end
end
end
# DELETE /calendars/1
# DELETE /calendars/1.json
def destroy
@user = current_user
@calendar.destroy
authorize @calendar
respond_to do |format|
format.html { redirect_to calendars_url, notice: 'Calendar was successfully destroyed.' }
format.json { head :no_content }
end
end
并且我在 ApplicationController
中加入了 after_action :verify_authorized, :except => :index
。
现在,当我登录时,我可以访问 http://localhost:3000/calendars/
,但是当我尝试访问 http://localhost:3000/calendars/new
时,出现以下错误:
Pundit::NotAuthorizedError in CalendarsController#new
not allowed to new? this #<Calendar id: nil, name: nil, created_at: nil, updated_at: nil>
@user = current_user
@calendar = @user.calendars.new
authorize @calendar
end
显然,我一定是做错了什么。
问题:我不知道是什么。
有什么想法吗?
您无权访问模型中的参数,除非您传递它们。您应该将日历传递给模型实例函数,并且您已经可以访问用户。
user.editor?(calendar)
def editor?(calendar)
Administration.find_by(user_id: self.id, calendar_id: calendar.id).role == "Editor"
end
问题是我没有在 CalendarPolicy 中定义 create
操作。
由于 CalendarPolicy 继承自 ApplicationPolicy — CalendarPolicy < ApplicationPolicy
— 并且 ApplicationPolicy 中的 create
操作默认设置为 false
,因此我遇到了错误。
只需将以下代码添加到 CalendarPolicy
即可解决问题:
def create?
true
end
额外提示:无需向CalendarPolicy
添加新操作,因为我们在ApplicationPolicy
中已有以下代码:
def new?
create?
end
在我的Rails4个应用中,有5个模型:
class User < ActiveRecord::Base
has_many :administrations
has_many :calendars, through: :administrations
end
class Calendar < ActiveRecord::Base
has_many :administrations
has_many :users, through: :administrations
has_many :posts
end
class Administration < ActiveRecord::Base
belongs_to :user
belongs_to :calendar
end
class Post < ActiveRecord::Base
belongs_to :calendar
end
class Comment < ActiveRecord::Base
belongs_to :post
belongs_to :user
end
我使用 Devise 实现了身份验证(因此我们可以访问 current_user
)。
现在,我正在尝试使用 Pundit(第一个定时器)实现授权。
在 documentation 之后,我安装了 gem 和 运行 rails g pundit:install
生成器。
然后,我创建了一个CalendarPolicy
,如下:
class CalendarPolicy < ApplicationPolicy
attr_reader :user, :calendar
def initialize(user, calendar)
@user = user
@calendar = calendar
end
def index?
user.owner? || user.editor? || user.viewer?
end
def show?
user.owner? || user.editor? || user.viewer?
end
def update?
user.owner? || user.editor?
end
def edit?
user.owner? || user.editor?
end
def destroy?
user.owner?
end
end
我还使用以下方法更新了我的 User
模型:
def owner?
Administration.find_by(user_id: params[:user_id], calendar_id: params[:calendar_id]).role == "Owner"
end
def editor?
Administration.find_by(user_id: params[:user_id], calendar_id: params[:calendar_id]).role == "Editor"
end
def viewer?
Administration.find_by(user_id: params[:user_id], calendar_id: params[:calendar_id]).role == "Viewer"
end
我用 authorize @calendar
更新了我的 CalendarsController
操作,如下:
def index
@user = current_user
@calendars = @user.calendars.all
end
# GET /calendars/1
# GET /calendars/1.json
def show
@user = current_user
@calendar = @user.calendars.find(params[:id])
authorize @calendar
end
# GET /calendars/new
def new
@user = current_user
@calendar = @user.calendars.new
authorize @calendar
end
# GET /calendars/1/edit
def edit
@user = current_user
authorize @calendar
end
# POST /calendars
# POST /calendars.json
def create
@user = current_user
@calendar = @user.calendars.create(calendar_params)
authorize @calendar
respond_to do |format|
if @calendar.save
current_user.set_default_role(@calendar.id, 'Owner')
format.html { redirect_to calendar_path(@calendar), notice: 'Calendar was successfully created.' }
format.json { render :show, status: :created, location: @calendar }
else
format.html { render :new }
format.json { render json: @calendar.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /calendars/1
# PATCH/PUT /calendars/1.json
def update
@user = current_user
@calendar = Calendar.find(params[:id])
authorize @calendar
respond_to do |format|
if @calendar.update(calendar_params)
format.html { redirect_to calendar_path(@calendar), notice: 'Calendar was successfully updated.' }
format.json { render :show, status: :ok, location: @calendar }
else
format.html { render :edit }
format.json { render json: @calendar.errors, status: :unprocessable_entity }
end
end
end
# DELETE /calendars/1
# DELETE /calendars/1.json
def destroy
@user = current_user
@calendar.destroy
authorize @calendar
respond_to do |format|
format.html { redirect_to calendars_url, notice: 'Calendar was successfully destroyed.' }
format.json { head :no_content }
end
end
并且我在 ApplicationController
中加入了 after_action :verify_authorized, :except => :index
。
现在,当我登录时,我可以访问 http://localhost:3000/calendars/
,但是当我尝试访问 http://localhost:3000/calendars/new
时,出现以下错误:
Pundit::NotAuthorizedError in CalendarsController#new
not allowed to new? this #<Calendar id: nil, name: nil, created_at: nil, updated_at: nil>
@user = current_user
@calendar = @user.calendars.new
authorize @calendar
end
显然,我一定是做错了什么。
问题:我不知道是什么。
有什么想法吗?
您无权访问模型中的参数,除非您传递它们。您应该将日历传递给模型实例函数,并且您已经可以访问用户。
user.editor?(calendar)
def editor?(calendar)
Administration.find_by(user_id: self.id, calendar_id: calendar.id).role == "Editor"
end
问题是我没有在 CalendarPolicy 中定义 create
操作。
由于 CalendarPolicy 继承自 ApplicationPolicy — CalendarPolicy < ApplicationPolicy
— 并且 ApplicationPolicy 中的 create
操作默认设置为 false
,因此我遇到了错误。
只需将以下代码添加到 CalendarPolicy
即可解决问题:
def create?
true
end
额外提示:无需向CalendarPolicy
添加新操作,因为我们在ApplicationPolicy
中已有以下代码:
def new?
create?
end