Rails 4:CanCanCan能力与has_many:通过关联 [英] Rails 4: CanCanCan abilities with has_many :through association

查看:468
本文介绍了Rails 4:CanCanCan能力与has_many:通过关联的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个具有以下型号的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:我一直在做一些研究,我意识到我犯了两个错误。


  1. 我没有将 load_and_authorize_resource 添加到日历管理控制器


  2. 我已经定义了两个参数 - 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) users can create new calendars.
  • If a user is the owner of a calendar, then he can manage the calendar and all the administrations that belong to this calendar, including his own administration.
  • If a user is editor of a calendar, then he can read and update this calendar, and destroy his administration.
  • If a user is viewer of a calendar, then he can read this calendar, and destroy his administration.

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 users 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.

  1. I had not added load_and_authorize_resource to the calendars and administrations controllers.

  2. I had defined two attributes two parameters — initialize(user, calendar) — instead of one in my initialize 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:通过关联的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆