使用Rails3 / Devise的CanCan方法的问题

时间:2013-02-01 12:47:04

标签: ruby-on-rails devise cancan

两天后,我自己无法解决这个问题。看起来它应该很简单,但我遗漏了一些东西。我正在创建一个包含帖子和作者的简单博客。作者有一个布尔管理列。

现在给我一个错误的行是我检查权限以显示帖子中的编辑按钮。当前错误是:

帖子中的NoMethodError#show

显示...... / posts / show.html.erb,其中第18行引发:

的未定义方法`stringify_keys'

文章/ show.html.rb

          <% if @author.can? :update, @post %>
          <p><%= link_to 'Edit', edit_post_path(@post), :class => 'btn' %> &nbsp; <%= link_to 'Destroy', @post, confirm: 'Are you sure?', method: :delete %></p>
          <% end %>

application_controller.rb

class ApplicationController < ActionController::Base
  protect_from_forgery  
  rescue_from CanCan::AccessDenied do |exception|
    redirect_to root_url, :alert => exception.message
  end
  helper_method :current_author
  def current_user
    @current_ability ||= Author.new(current_author)
  end
end

ability.rb

class Ability
  include CanCan::Ability
  def initialize(author)
    author ||= Author.new # guest user (not logged in)   
    if author.admin?
      can :manage, :all
    else
      can :read, :all
    end  
  end
end

另外,据我所知,CanCan正确地包含在gem文件中。

1 个答案:

答案 0 :(得分:1)

两件事。

首先,您需要在控制器中使用current_user方法,cancan可以依赖该方法。如果你没有,你可以

  • 别名current_user到您的current_whatever方法或
  • 手动实例化@ability = Ability.new(current_whatever)之类的功能,并在您的观看次数中调用您生成的can?个功能(例如@ability.can? :edit, @post)。

其次,您的Ability在第4行和第5行都使用current_author,但您的current_author方法中没有initialize。但是你有author。如果没有Author对象可用/给予该能力的初始化程序,则使用非持久作者(而不是AuthorAbility,除非您的AuthorAbility是current_user返回的内容或initialize能力作为参数)。像这样:

class Ability
  include CanCan::Ability
  def initialize(author)
    author ||= Author.new # guest user (not logged in)
    if author.admin?
      can :manage, :all
    else
      can :read, :all
    end  
  end
end

根据评论进行编辑以使其更简单:

理想情况下,您在应用程序控制器中放置了current_user方法,并在视图中将其作为帮助程序使用(因为您可能希望根据登录用户有条件地显示/隐藏/更改视图中的内容)。

class ApplicationController < ActionController::Base
  helper_method :current_user

  def current_user
    # return the currently logged in user record
  end
end

如果您不熟悉,我建议您查看身份验证宝石。 Devise还介绍了这一点,authlogic在其操作方法和示例应用程序中对此进行了描述。如果您从头开始进行身份验证,则只需根据会话返回用户。


编辑2.你实际上需要了解你的所作所为,目前恕我直言。你在这里做得有点混乱;-)

问题1:current_user需要返回当前作者/用户登​​录(不是内容或后退用户或其他内容)或nil如果没有记录作者在。所以你可以例如在您的视图中执行<% if current_user %>@current_ability ||= Author.new(current_author)是完全错误的。能力类的后退需要保留在能力类中,因为cancan的方法只能应用于对象而不能应用于nil。因此,使用author ||= Author.new,即使没有作者登录,也要确保有对象(在这种情况下current_author会返回nil)。

问题2:helper_method :current_author实际上什么也没做,因为应用程序控制器中没有current_author方法。您需要以某种方式定义current_author

问题3:在您看来,您在can?的实例上调用了Author这是错误的。 can?Ability的一种方法。因此,您需要使用@my_ability.can?,其中@my_ability是例如Ability.new(Author.first)。如果您需要使用多种功能或自定义某些功能,则会使用此功能,而这种情况并非如此,所以只需在没有接收器的情况下直接使用can?(例如@author.can?)。

出于测试目的,我将创建以下内容:

class ApplicationController < ActionController::Base
  helper_method :current_user # as defined below...

  def current_user
    # Return a static user here, for testing purposes,
    # like @current_user = User.first or Author.first
  end
end

所以你的current_user会返回一个有效的用户(我希望你至少需要在数据库中存储一个用户),然后才能解决能力问题。如果您的能力有效,则可以实施身份验证。作为初学者,我要么坚持authlogicdevise