Rails 4:CanCanCan能力与has_many:通过关联

时间:2015-09-02 00:37:23

标签: ruby-on-rails ruby-on-rails-4 devise cancan cancancan

我有一个带有以下型号的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

对于给定的calendaruser有一个role,它在administration联接模型中定义。

对于每个日历,用户只能拥有以下三种角色中的一种:OwnerEditorViewer

这些角色目前没有存储在字典或常量中,只能通过不同的方法作为字符串(“Ower”,“Editor”,“Viewer”)分配给管理。

User模型上的身份验证是通过Devise处理的,current_user方法正在运行。

为了仅允许登录用户访问应用内资源,我已在before_action :authenticate_user!calendars控制器中添加了administrations方法。

现在,我需要实现一个基于角色的授权系统,所以我刚刚安装了CanCanCan gem。

这是我想要实现的目标:

  • 所有(已登录)user可以创建新的calendar
  • 如果userowner的{​​{1}},那么他可以calendar manage以及属于calendar的所有administration对此calendar,包括他自己的administration
  • 如果用户是editor的{​​{1}},那么他可以calendarread此日历,并销毁他的update
  • 如果administrationuser的{​​{1}},那么他viewer calendarread 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,我对我的代码不太自信,并希望得到一些验证或改进建议。

那么,这段代码是否有效,是否可以让我实现我的需求?

更新:使用当前代码,当我以用户身份登录,并访问其他用户日历的日历#show页面时,我实际上可以访问日历,我不应该这样做。< / p>

所以,显然,我的代码无效。

知道我做错了什么?

更新2 :我认为我的代码中存在错误,因为我使用:model代替Model来允许user执行操作给定model

但是,代码仍无效。

知道这里可能出现什么问题?

更新3 :问题可能是由于我使用if user.role?(:owner)检查用户的角色是否设置为所有者,而在数据库中角色实际定义为“所有者”(作为字符串)?

更新4:我继续做一些研究,我意识到我犯了两个错误。

  1. 我没有将load_and_authorize_resource添加到calendarsadministrations控制器。

  2. 我在两个参数中定义了两个参数 - initialize(user, calendar) - 而不是initialize方法中的一个。

  3. 因此,更新了两个控制器以及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
    

    我如何解决这个问题?

1 个答案:

答案 0 :(得分:1)

User模型没有这样的方法role?。假设示例中存在这样的方法,Cancancan文档是错误的。

要解决此问题,您应该执行以下操作:

if user.role == 'Owner'
  ...
elsif user.role == 'Editor'
  ...
elsif user.role == 'Viewer'
  ...