问题描述
我有一个具有以下型号的Rails应用程序:
class User< ActiveRecord :: Base
has_many:administrations
has_many:日历,通过::管理
end
class Calendar& ActiveRecord :: Base
has_many:administrationments
has_many:users,through::administrations
end
class Administration< ActiveRecord :: Base
belongs_to:user
belongs_to:calendar
end
对于给定的日历
,用户
具有角色
,它在管理
连接模型中定义。
对于每个日历,用户只能有一个以下三个角色:所有者
,编辑器
或查看器
。
这些角色目前不存储在字典或常量中,只能通过字符串(Ower,Editor,Viewer)分配给管理员不同的方法。
通过Devise处理用户
模型的身份验证,而 current_user
方法正在运行。
为了仅允许登录的用户访问应用内资源,我已经添加了 before_action:authenticate_user!
方法在日历
和管理员
p>
现在,我需要实现一个基于角色的授权系统,所以我刚刚安装了 CanCanCan
gem。
这是我想要实现的:
- 全部(登录)
code> s可以创建新的
日历
。 - 如果一个
用户
是日历
的所有者
,那么他可以管理
日历
和属于此日历的所有
,包括他自己的管理
s管理
。 - 如果用户是
编辑器
日历
,那么他可以读取
和更新
这个日历,并销毁他的管理
。 如果一个
用户
code>查看器日历
,那么他可以读取
这个日历
和destroy
他的管理
。
为了实现上述,我已经提出了以下 ability.rb
文件:
类能力
包括CanCan ::能力
def初始化(用户,日历)
用户|| = User.new
calendar = Calendar.find(params [:id] )
用户可以:创建,:日历
如果user.role?(:owner)
可以:管理,:日历,:user_id => user.id
可以:管理,:管理,:user_id => user.id
可以:管理,:管理,:calendar_id => calendar.id
elsif user.role?(:editor)
可以[:read,:update],:calendar,:user_id => user.id
can:destroy,:administration,:user_id => user.id
elsif user.role?(:viewer)
可以[:read],:calendar,:user_id => user.id
can:destroy,:administration,:user_id => user.id
end
end
end
自从我没有很好的尝试使用Rails,这是我第一次使用 CanCanCan
,我对我的代码并不十分有信心,并希望得到一些验证或建议。 p>
所以,这段代码是否可以正常工作,是否可以实现我需要的?
更新:使用当前的代码,当我以用户身份登录,并访问另一个用户日历的日历#显示页面时,我实际可以访问日历,我不应该。
显然,我的代码不起作用。
任何想法我做错了什么?
更新2 :我认为我的代码有错误,因为我使用:model
而不是模型
允许用户
在给定的模型
上执行操作。 p>
但是,代码仍然不起作用。
更新3 :问题可能是由于我使用 if user.role?(:owner)
检查用户的角色是否设置为所有者,而在数据库中角色实际上被定义为所有者(作为字符串)?
更新4:我一直在做一些研究,我意识到我犯了两个错误。
-
我没有将
load_and_authorize_resource
添加到日历
和管理
控制器 -
我已经定义了两个参数 -
initialize(user,calendar)
- 而不是我的初始化
方法中的一个。
所以,更新了两个控制器,以及capability.rb文件如下:
class Ability
包括CanCan :: Ability
def initialize(user)
user || = User.new
if user.role?(:owner)
可以:管理,日历,:user_id => user.id
可以:管理,管理,:user_id => user.id
可以:管理,管理,:calendar_id => calendar.id
elsif user.role?(:editor)
可以[:read,:update],Calendar,:user_id => user.id
can:destroy,Administration,:user_id => user.id
elsif user.role?(:viewer)
可以[:read],Calendar,:user_id => user.id
can:destroy,Administration,:user_id => user.id
end
end
end
现在,当我尝试访问不属于 current_user
的日历,我收到以下错误:
CalendarsController中的NoMethodError#show
undefined方法`role?'for#< User:0x007fd003dff860>
def initialize(user)
user || = User.new
如果user.role?(:owner)
可以:管理,日历,:user_id => user.id
可以:管理,管理,:user_id => user.id
可以:管理,管理,:calendar_id => calendar.id
我如何解决这个问题?
没有这样的方法角色?
用户模型。 Cancancan文档是错误的,假设这种方法存在于示例中。
要解决这个问题,你应该这样做:
if user.role =='Owner'
...
elsif user.role =='Editor'
...
elsif user.role =='Viewer'
...
I have a Rails app with the following models:
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
end
class Administration < ActiveRecord::Base
belongs_to :user
belongs_to :calendar
end
For a given calendar
, a user
has a role
, which is define in the administration
join model.
For each calendar, a user can have only one of the following three roles: Owner
, Editor
or Viewer
.
These roles are currently not stored in dictionary or a constant, and are only assigned to an administration as strings ("Ower", "Editor", "Viewer") through different methods.
Authentication on the User
model is handled through Devise, and the current_user
method is working.
In order to only allow logged-in users to access in-app resources, I have already add the before_action :authenticate_user!
method in the calendars
and administrations
controllers.
Now, I need to implement a role-based authorization system, so I just installed the CanCanCan
gem.
Here is what I want to achieve:
- All (logged-in)
user
s can create newcalendar
s. - If a
user
is theowner
of acalendar
, then he canmanage
thecalendar
and all theadministration
s that belong to thiscalendar
, including his ownadministration
. - If a user is
editor
of acalendar
, then he canread
andupdate
this calendar, and destroy hisadministration
. - If a
user
isviewer
of acalendar
, then he canread
thiscalendar
, anddestroy
hisadministration
.
To implement the above, I have come up with the following ability.rb
file:
class Ability
include CanCan::Ability
def initialize(user, calendar)
user ||= User.new
calendar = Calendar.find(params[:id])
user can :create, :calendar
if user.role?(:owner)
can :manage, :calendar, :user_id => user.id
can :manage, :administration, :user_id => user.id
can :manage, :administration, :calendar_id => calendar.id
elsif user.role?(:editor)
can [:read, :update], :calendar, :user_id => user.id
can :destroy, :administration, :user_id => user.id
elsif user.role?(:viewer)
can [:read], :calendar, :user_id => user.id
can :destroy, :administration, :user_id => user.id
end
end
end
Since I am not very experimented with Rails and it is the first time I am working with CanCanCan
, I am not very confident with my code and would like some validation or advice for improvement.
So, would this code work, and would it allow me to achieve what I need?
UPDATE: with the current code, when I log in as a user, and visit the calendars#show page of another user's calendar, I can actually access the calendar, which I should not.
So, obviously, my code is not working.
Any idea of what I am doing wrong?
UPDATE 2: I figured there were errors in my code, since I was using :model
instead of Model
to allow user
s to perform actions on a given model
.
However, the code is still not working.
Any idea of what could be wrong here?
UPDATE 3: could the issue be caused by the fact that I use if user.role?(:owner)
to check if a user's role is set to owner, while in the database the role is actually defined as "Owner" (as a string)?
UPDATE 4: I kept on doing some research and I realized I had done two mistakes.
I had not added
load_and_authorize_resource
to thecalendars
andadministrations
controllers.I had defined two attributes two parameters —
initialize(user, calendar)
— instead of one in myinitialize
method.
So, updated both controllers, as well as the ability.rb file as follows:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new
if user.role?(:owner)
can :manage, Calendar, :user_id => user.id
can :manage, Administration, :user_id => user.id
can :manage, Administration, :calendar_id => calendar.id
elsif user.role?(:editor)
can [:read, :update], Calendar, :user_id => user.id
can :destroy, Administration, :user_id => user.id
elsif user.role?(:viewer)
can [:read], Calendar, :user_id => user.id
can :destroy, Administration, :user_id => user.id
end
end
end
Now, when I try to visit a calendar that does not belong to the current_user
, I get the following error:
NoMethodError in CalendarsController#show
undefined method `role?' for #<User:0x007fd003dff860>
def initialize(user)
user ||= User.new
if user.role?(:owner)
can :manage, Calendar, :user_id => user.id
can :manage, Administration, :user_id => user.id
can :manage, Administration, :calendar_id => calendar.id
How I can fix this?
There is no such method role?
the User model. The Cancancan documentation is at fault for assuming such a method exists in the examples.
To fix this, you should instead do:
if user.role == 'Owner'
...
elsif user.role == 'Editor'
...
elsif user.role == 'Viewer'
...
这篇关于Rails 4:CanCanCan能力与has_many:通过关联的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!