Rails 5中CanCanCan 2.0.0作用域权限定义问题咨询
Alright, let's tackle this CanCanCan 2.0.0 permission setup for your archived articles scenario. Here's how to properly define permissions that work with your two list actions and shared partial:
1. Refine Your Ability Class
First, we'll explicitly define permissions for both regular and archived articles, tailored to the :archived_access role. This ensures CanCanCan knows exactly which records each user can access:
class Ability def initialize(user = User.new) # Default for unauthenticated/regular users: only access non-archived articles can :read, Article, archived: false if user.has_role?(:archived_access) # Revoke default access to non-archived articles (if needed) cannot :read, Article, archived: false # Grant access ONLY to archived articles (using your existing scope) can :read, Article.archived # If you need to allow specific actions (like show, or custom list actions), specify them: # can [:index, :show], Article.archived end end end
2. Secure Your Controller Actions
In your articles controller, use CanCanCan's accessible_by method to filter records at the database level—this is critical for security, as it prevents unauthorized records from being loaded even if someone bypasses view checks.
Assuming your two list actions are index (regular articles) and archived (archived articles):
class ArticlesController < ApplicationController def index # Load only non-archived articles the user can access @articles = Article.accessible_by(current_ability) end def archived # Load only archived articles the user can access @articles = Article.archived.accessible_by(current_ability) end end
3. Adapt the Shared Partial
Since your partial is shared between both lists, use CanCanCan's can? helper to conditionally render elements based on the user's permissions for the specific article. For example, if you have edit/delete buttons:
# app/views/articles/_article.html.erb <div class="article"> <h3><%= article.title %></h3> <p><%= article.content %></p> <%# Only show edit button if user can update this article %> <% if can? :update, article %> <%= link_to "Edit", edit_article_path(article) %> <% end %> </div>
Key Notes
- Database-level filtering: Always use
accessible_byin controllers—view-levelcan?checks are for UI purposes, not security. - Scope compatibility: CanCanCan 2.0.0 works seamlessly with ActiveRecord scopes, so using
Article.archiveddirectly in thecanmethod is safe and clean. - Flexibility: If you need more complex logic (e.g., a user can access both regular and archived articles), just adjust the
Abilityrules—remove thecannotline for the:archived_accessrole, and keep bothcandefinitions.
内容的提问来源于stack exchange,提问作者fabianraf

