简体   繁体   English

Rails3 / Devise的CanCan方法存在问题

[英]Problems with CanCan Methods with Rails3 / Devise

After two days, I've not been able to solve this problem on my own. 两天后,我无法自行解决此问题。 It seems like it should be pretty simple, but I'm missing something. 看起来应该很简单,但是我缺少了一些东西。 I'm creating a simple blog with Posts and Authors. 我正在用Posts and Authors创建一个简单的博客。 Authors have a boolean admin column. 作者有一个布尔admin列。

The line that is giving me an error right now is where I check permissions to show the edit button in a post.Current error is: 现在出现错误的行是我检查权限以在帖子中显示编辑按钮的地方。当前错误是:

NoMethodError in Posts#show Posts#show中的NoMethodError

Showing .../posts/show.html.erb where line #18 raised: 在第18行出现的位置显示... / posts / show.html.erb:

undefined method `stringify_keys' for # #的未定义方法`stringify_keys'

posts/show.html.rb 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 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

Also, from what I can tell, CanCan is included in the gem file correctly. 另外,据我所知,CanCan正确包含在gem文件中。

Two things. 两件事情。

First, you need to have a current_user method in your controller, on which cancan relies. 首先,您需要在控制器中有一个can_can依赖的current_user方法。 If you don't have one, you may 如果您没有一个,可以

  • alias current_user to your current_whatever method or 别名current_usercurrent_whatever方法或
  • manually instantiate the ability like @ability = Ability.new(current_whatever) and call your can? 手动实例化诸如@ability = Ability.new(current_whatever)然后打电话给您can? 's on that generated ability in your views (like @ability.can? :edit, @post ). 在您认为的生成能力上(例如@ability.can? :edit, @post )。

Second, your Ability uses current_author on both line 4 and 5, however you don't have a current_author in your initialize method. 其次,您的Ability在第4行和第5行都使用current_author ,但是您的initialize方法中没有current_author You have author , though. 不过,您有author If no Author object is available/given to the ability's initializer, you use a non-persisted author instead (and not a AuthorAbility, unless your AuthorAbility is what current_user returns or initialize in your ability gets as argument). 如果该功能的初始化程序没有可用的Author对象,则使用非持久性作者(而不是AuthorAbility,除非AuthorAbility是current_user返回或在您的功能中进行initialize东西作为参数)。 Something like this: 像这样:

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

Edit based on the comments to keep it simpler: 根据评论进行编辑以使其更简单:

Ideally you put a current_user method inside your application controller and also make it available as helper in your views (because you may want to conditionally show/hide/change things in your view based on a logged-in user). 理想情况下,将current_user方法放入应用程序控制器中,并在视图中将其用作帮助程序(因为您可能希望基于登录的用户有条件地在视图中显示/隐藏/更改内容)。

class ApplicationController < ActionController::Base
  helper_method :current_user

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

If this is new to you, I suggest to have a look at an authentication gem. 如果这对您来说是新手,我建议您看一下身份验证宝。 Devise also introduces this and authlogic describes this in its how-to and the example application. Devise也对此进行了介绍,而authlogic在其使用方法和示例应用程序中对此进行了描述。 If you're doing authentication from scratch, you just need to return the user based on the session. 如果您要从头开始进行身份验证,则只需根据会话返回用户。


edit 2. You actually need to understand what you do, which IMHO is not the case at the moment. 编辑2.您实际上需要了解您的操作,恕我直言,目前情况并非如此。 You're doing a bit of a mess here ;-) 你在这里有点混乱;-)

Problem 1: current_user needs to return the current author / user logged in (not an abilty nor fallback user nor something else) or nil if no author is logged in. So you can eg do <% if current_user %> in your view. 问题1: current_user需要返回当前登录的作者/用户 (不是abilty,fallback用户或其他身份),如果没有作者登录,则返回nil 。因此,例如,您可以在视图中执行<% if current_user %> @current_ability ||= Author.new(current_author) is plain wrong. @current_ability ||= Author.new(current_author)是完全错误的。 The fallback from the ability class needs to stay in the ability class because cancan's methods can only be applied to an object and not to nil . 来自能力类的后退需要保留在能力类中,因为cancan的方法只能应用于对象,而不能应用于nil So with author ||= Author.new in your ability, you make sure that there is an object, even if no author is logged in (in which case current_author returns nil ). 因此,如果您具有author ||= Author.new ,即使没有作者登录,也请确保存在一个对象(在这种情况下, current_author返回nil )。

Problem 2: helper_method :current_author actually does nothing because there is no current_author method in your application controller. 问题2: helper_method :current_author实际上不执行任何操作,因为您的应用程序控制器中没有current_author方法。 You need to somehow define current_author . 您需要以某种方式定义current_author

Problem 3: In your view, you're calling can? 问题3:在您看来,您在打电话can? on an instance of Author which is wrong. 在一个Author实例上,这是错误的。 can? is a method of Ability . 是一种Ability的方法。 So you'd need to use @my_ability.can? 因此,您需要使用@my_ability.can? where @my_ability is an instance of eg Ability.new(Author.first) . 其中@my_ability是例如Ability.new(Author.first)的实例。 This is used if you need to work with multiple abilities or customized something, which is not the case here, so just use can? 如果您需要使用多种能力或自定义某些内容,则使用此方法,此处不是这种情况,那么使用can? directly without a receiver (like @author.can? ). 直接没有接收者(例如@author.can? )。

For testing purposes, I'd create the following: 为了进行测试,我将创建以下内容:

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

So your current_user returns a valid user (I hope, you need to at least have one in your database stored, though) and then can sort out the ability issues. 因此,您的current_user返回一个有效用户(不过,我希望您至少需要在数据库中存储一个用户),然后才能解决能力问题。 If your ability works, you implement your authentication. 如果您的能力有效,则可以实施身份验证。 As a beginner, I'd either stick to authlogic or devise . 作为一个初学者,我要么坚持authlogic要么设计一个

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM