这是一个关于
Rails 4: CanCanCan abilities with has_many :through association的后续问题,我在这里重申了这个问题,因为我认为上下文略有变化,经过4次更新后,最初问题的代码也大不相同.
我还检查了其他问题,比如Undefined method ‘role?’ for User,但它没有解决我的问题.
那么,我们走了:我有三个型号:
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
对于给定日历,用户具有角色,该角色在管理连接模型中定义(在名为role的列中).
对于每个日历,用户只能拥有以下三种角色之一:所有者,编辑者或查看者.
这些角色当前未存储在字典或常量中,并且仅通过不同方法作为字符串(“Ower”,“Editor”,“Viewer”)分配给管理.
用户模型上的身份验证通过Devise处理,current_user方法正在运行.
为了只允许登录用户访问应用内资源,我已经添加了before_action:authenticate_user!日历和管理控制器中的方法.
现在,我需要实现一个基于角色的授权系统,所以我刚刚安装了CanCanCan gem.
这是我想要实现的目标:
>所有(已登录)用户都可以创建新日历.
>如果用户是日历的所有者,则他可以管理日历和属于此日历的所有管理,包括他自己的管理.
>如果用户是日历的编辑者,那么他可以阅读并更新此日历,并销毁他的管理.
>如果用户是日历的查看者,那么他可以阅读此日历,并销毁他的管理.
为实现上述目的,我提出了以下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
现在,当登录并尝试访问任何日历页面(索引,显示,编辑)时,我收到以下错误:
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
我想问题来自这样一个事实,即用户本身没有角色,但只有一个为给定日历定义的角色.
这解释了为什么我得到角色的NoMethodError?在用户上.
那么,问题是:如何检查给定日历的用户角色?
知道如何让事情发挥作用吗?
最佳答案 你应该有角色吗?用户模型中的方法,如下所示 –
class User < ActiveRecord::Base
has_many :administrations
has_many :calendars, through: :administrations
def role?(type)
administrations.pluck(:role).include?(type.to_s)
end
end