Rails 4: CanCanCan abilities with has_many :through association
Rails 4: CanCanCan abilities with has_many :through association
我有一个 Rails 应用程序,具有以下型号:
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
对于给定的 calendar
,user
有一个 role
,它在 administration
连接模型中定义。
对于每个日历,用户只能拥有以下三种角色之一:Owner
、Editor
或 Viewer
。
这些角色目前未存储在字典或常量中,仅通过不同方法以字符串形式("Ower"、"Editor"、"Viewer")分配给管理部门。
User
模型上的身份验证是通过 Devise 处理的,current_user
方法有效。
为了只允许登录用户访问应用内资源,我已经在calendars
和administrations
控制器中添加了before_action :authenticate_user!
方法
现在,我需要实现一个基于角色的授权系统,所以我只安装了 CanCanCan
gem.
这是我想要实现的目标:
- 所有(已登录)
user
可以创建新的 calendar
。
- 如果
user
是calendar
的owner
,那么他可以manage
calendar
和所有administration
属于这个 calendar
,包括他自己的 administration
。
- 如果一个用户是
calendar
的editor
,那么他可以read
和update
这个日历,并销毁他的administration
。
- 如果一个
user
是一个calendar
的viewer
,那么他可以read
这个calendar
,destroy
他的administration
.
为了实现上述内容,我提出了以下 ability.rb
文件:
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
由于我对 Rails 的实验并不多,而且这是我第一次使用 CanCanCan
,我对我的代码不是很有信心,希望得到一些验证或改进建议.
那么,这段代码是否有效,它是否能让我实现我所需要的?
UPDATE:使用当前代码,当我以用户身份登录并访问另一个用户日历的calendars#show页面时,我实际上可以访问日历,这我不应该。
所以,很明显,我的代码不起作用。
知道我做错了什么吗?
更新 2:我认为我的代码中存在错误,因为我使用 :model
而不是 Model
来允许 user
s 对给定的 model
.
执行操作
但是,代码仍然无效。
知道这里有什么问题吗?
更新 3:问题可能是由于我使用 if user.role?(:owner)
检查用户的角色是否设置为所有者,而在数据库中角色实际上定义为 "Owner"(作为字符串)?
更新 4:我继续做一些研究,我意识到我犯了两个错误。
我没有将 load_and_authorize_resource
添加到 calendars
和 administrations
控制器。
我定义了两个属性和两个参数 — initialize(user, calendar)
— 而不是我的 initialize
方法中的一个。
因此,更新两个控制器以及 ability.rb 文件如下:
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
现在,当我尝试访问不属于 current_user
的日历时,出现以下错误:
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
我该如何解决这个问题?
用户模型没有这样的方法role?
。 Cancancan 文档错误地假设示例中存在这种方法。
要解决这个问题,您应该这样做:
if user.role == 'Owner'
...
elsif user.role == 'Editor'
...
elsif user.role == 'Viewer'
...
我有一个 Rails 应用程序,具有以下型号:
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
对于给定的 calendar
,user
有一个 role
,它在 administration
连接模型中定义。
对于每个日历,用户只能拥有以下三种角色之一:Owner
、Editor
或 Viewer
。
这些角色目前未存储在字典或常量中,仅通过不同方法以字符串形式("Ower"、"Editor"、"Viewer")分配给管理部门。
User
模型上的身份验证是通过 Devise 处理的,current_user
方法有效。
为了只允许登录用户访问应用内资源,我已经在calendars
和administrations
控制器中添加了before_action :authenticate_user!
方法
现在,我需要实现一个基于角色的授权系统,所以我只安装了 CanCanCan
gem.
这是我想要实现的目标:
- 所有(已登录)
user
可以创建新的calendar
。 - 如果
user
是calendar
的owner
,那么他可以manage
calendar
和所有administration
属于这个calendar
,包括他自己的administration
。 - 如果一个用户是
calendar
的editor
,那么他可以read
和update
这个日历,并销毁他的administration
。 - 如果一个
user
是一个calendar
的viewer
,那么他可以read
这个calendar
,destroy
他的administration
.
为了实现上述内容,我提出了以下 ability.rb
文件:
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
由于我对 Rails 的实验并不多,而且这是我第一次使用 CanCanCan
,我对我的代码不是很有信心,希望得到一些验证或改进建议.
那么,这段代码是否有效,它是否能让我实现我所需要的?
UPDATE:使用当前代码,当我以用户身份登录并访问另一个用户日历的calendars#show页面时,我实际上可以访问日历,这我不应该。
所以,很明显,我的代码不起作用。
知道我做错了什么吗?
更新 2:我认为我的代码中存在错误,因为我使用 :model
而不是 Model
来允许 user
s 对给定的 model
.
但是,代码仍然无效。
知道这里有什么问题吗?
更新 3:问题可能是由于我使用 if user.role?(:owner)
检查用户的角色是否设置为所有者,而在数据库中角色实际上定义为 "Owner"(作为字符串)?
更新 4:我继续做一些研究,我意识到我犯了两个错误。
我没有将
load_and_authorize_resource
添加到calendars
和administrations
控制器。我定义了两个属性和两个参数 —
initialize(user, calendar)
— 而不是我的initialize
方法中的一个。
因此,更新两个控制器以及 ability.rb 文件如下:
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
现在,当我尝试访问不属于 current_user
的日历时,出现以下错误:
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
我该如何解决这个问题?
用户模型没有这样的方法role?
。 Cancancan 文档错误地假设示例中存在这种方法。
要解决这个问题,您应该这样做:
if user.role == 'Owner'
...
elsif user.role == 'Editor'
...
elsif user.role == 'Viewer'
...