【问题标题】:Problems with CanCan Methods with Rails3 / DeviseRails3 / Devise 的 CanCan 方法的问题
【发布时间】:2013-02-01 12:47:03
【问题描述】:

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

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

帖子中的NoMethodError#show

显示 .../posts/show.html.erb 第 18 行出现的位置:

用于#的未定义方法`stringify_keys'

posts/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 文件中。

【问题讨论】:

    标签: ruby-on-rails devise cancan


    【解决方案1】:

    两件事。

    首先,你需要在你的控制器中有一个current_user 方法,cancan 依赖它。如果你没有,你可以

    • current_user 别名为current_whatever 方法或
    • 手动实例化类似@ability = Ability.new(current_whatever) 的功能,并在您的视图中调用您的can? 生成的功能(例如@ability.can? :edit, @post)。

    其次,您的 Ability 在第 4 行和第 5 行都使用 current_author,但是您的 initialize 方法中没有 current_author。不过,你有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
    

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

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

    class ApplicationController < ActionController::Base
      helper_method :current_user
    
      def current_user
        # return the currently logged in user record
      end
    end
    

    如果这对您来说是新的,我建议您看一下身份验证 gem。 Devise 还介绍了这一点,authlogic 在其操作指南和示例应用程序中对此进行了描述。如果您是从头开始进行身份验证,则只需根据会话返回用户即可。


    编辑 2. 您实际上需要了解您的工作,恕我直言,目前情况并非如此。你在这里做的有点乱 ;-)

    问题 1:current_user 需要返回 当前登录的作者/用户(不是 abilty 或后备用户或其他任何东西)或 nil 如果没有作者登录。所以你例如可以在你的视野中做&lt;% if current_user %&gt;@current_ability ||= Author.new(current_author) 完全错误。能力类的回退需要保留在能力类中,因为 cancan 的方法只能应用于对象,而不能应用于nil。因此,您可以使用author ||= Author.new 确保存在对象,即使没有作者登录(在这种情况下current_author 返回nil)。

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

    问题 3:在您看来,您在 Author 的实例上调用 can?,这是错误的。 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

    【讨论】:

    • 你能告诉我我的控制器中的 current_(author in this case) 方法应该是什么样子吗?我在入门文档中没有看到任何关于它的内容。 github.com/ryanb/cancan
    • 嗯? github.com/ryanb/cancan#getting-started 中的第一句话 ... 还有,github.com/ryanb/cancan/wiki/changing-defaults。 current_user 返回当前登录用户的实例。
    • 对不起,我对这一切都很陌生。我的眼睛直接跳过了那句话,转到第 1 点。当它说“CanCan 期望控制器中存在 current_user 方法”时,它是指应用程序控制器、作者控制器还是帖子控制器?其次,该方法应该是什么样的?第二部分关于更改默认值?谢谢。
    • 更新了一个新错误。不久前我遇到了同样的错误。不知道现在是更近了还是更远了。
    • FWIW 我也在使用 Friendly_ID 作为 URL,不确定它是否会影响任何东西。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多