How to configure Devise+Cancan correctly for guest

2019-08-30 11:24发布

问题:

In a Rails 3.2 app I'm using Devise + CanCan. The app previously restricted access to only logged in users. I'm in the process of adding a Guest user/ability that will be able to read certain sections of the site.

I'm having trouble understanding the "correct" way to set this up, specifically what combination of before_filter :authenticate! and load_and_authorize_resource is needed in controllers.

While working on this I've stripped the ability class to a minimum.

#Ability.rb
class Ability
  include CanCan::Ability

  def initialize(user_or_admin)
    user_or_admin ||= User.new

    can :manage, :all
  end
end

In a model-less/ static page Home controller

#home_controller.rb
class HomeController < ApplicationController
  load_and_authorize_resource
  def index
    ...some stuff
  end
end

and

#application_controller.rb
class ApplicationController < ActionController::Base
  protect_from_forgery
  before_filter :authenticate!
  ...more stuff
end

With this set up, un-logged-in users are redirected to Devise sign in page.

If I remove before_filter :authenticate! from the application controller I get an error uninitialized constant Home from activesupport-3.2.11/lib/active_support/inflector/methods.rb

If I remove load_and_authorize_resource from the home controller, this error goes away.

This is ok with my simplified testing Ability class, but as I start adding roles and abilities back in I will need to have CanCan handling the Home controller, i.e., will need load_and_authorize_resource to be called.

Can anyone help me understand why this error occurs when before_filter :authenticate! is removed, and point me towards any info that explain the "correct" way to set up Devise+Cancan for guest users. The info I've found thus far only explains how to set up the Ability class, not how to configure Devise.

回答1:

The problem is that there is no resource to authorize. Therefore, you need only call authorize_resource not load_and_authorize_resource. See authorizing controller actions in the cancan documentation for further information.

Update: You must also specify the class as false: authorize_resource class: false.

Then your home controller will look like this:

class HomeController < ActionController::Base
  authorize_resource class: false

  def show
    # automatically calls authorize!(:show, :home)
  end
end

This information is in the Non-RESTful controllers section. Sorry about that.