Loading...
Loading...
Compare original and translation side by side
undefinedundefined
This creates `app/models/ability.rb` where all authorization rules are defined.
这会创建`app/models/ability.rb`文件,所有授权规则都将在此定义。AbilityundefinedAbilityundefined# Signed-in users
return unless user.present?
can :read, Post
can :create, Post
can :update, Post, user_id: user.id
can :destroy, Post, user_id: user.id
can :create, Comment
can :update, Comment, user_id: user.id
can :destroy, Comment, user_id: user.id
# Admin users
return unless user.admin?
can :manage, :all # Can do anything
**Best Practice**: Structure rules hierarchically (guest → user → admin) for clarity.# Signed-in users
return unless user.present?
can :read, Post
can :create, Post
can :update, Post, user_id: user.id
can :destroy, Post, user_id: user.id
can :create, Comment
can :update, Comment, user_id: user.id
can :destroy, Comment, user_id: user.id
# Admin users
return unless user.admin?
can :manage, :all # Can do anything
**最佳实践**:按层级结构定义规则(访客→普通用户→管理员),提升可读性。:read # :index and :show
:create # :new and :create
:update # :edit and :update
:destroy # :destroy
:manage # All actions (use carefully!):read # :index and :show
:create # :new and :create
:update # :edit and :update
:destroy # :destroy
:manage # All actions (use carefully!)can :publish, Post
can :archive, Post
can :approve, Commentcan :publish, Post
can :archive, Post
can :approve, Commentcan :read, [Post, Comment, Category]
can :manage, [User, Post], user_id: user.idcan :read, [Post, Comment, Category]
can :manage, [User, Post], user_id: user.idundefinedundefinedundefinedundefinedundefinedundefined
**Important**: Block conditions cannot be used with `accessible_by` for database queries. Use hash conditions when you need to filter collections.
**重要提示**:块条件无法与`accessible_by`配合用于数据库查询。当需要过滤集合时,请使用哈希条件。undefinedundefinedundefinedundefinedclass PostsController < ApplicationController
def show
@post = Post.find(params[:id])
authorize! :read, @post # Raises CanCan::AccessDenied if not authorized
end
def update
@post = Post.find(params[:id])
authorize! :update, @post
if @post.update(post_params)
redirect_to @post
else
render :edit
end
end
endclass PostsController < ApplicationController
def show
@post = Post.find(params[:id])
authorize! :read, @post # Raises CanCan::AccessDenied if not authorized
end
def update
@post = Post.find(params[:id])
authorize! :update, @post
if @post.update(post_params)
redirect_to @post
else
render :edit
end
end
endclass PostsController < ApplicationController
load_and_authorize_resource
def index
# @posts automatically loaded with accessible_by
end
def show
# @post automatically loaded and authorized
end
def create
# @post initialized and authorized
if @post.save
redirect_to @post
else
render :new
end
end
def update
# @post loaded and authorized
if @post.update(post_params)
redirect_to @post
else
render :edit
end
end
endclass PostsController < ApplicationController
load_and_authorize_resource
def index
# @posts automatically loaded with accessible_by
end
def show
# @post automatically loaded and authorized
end
def create
# @post initialized and authorized
if @post.save
redirect_to @post
else
render :new
end
end
def update
# @post loaded and authorized
if @post.update(post_params)
redirect_to @post
else
render :edit
end
end
endundefinedundefinedundefinedundefinedundefinedundefined
**Performance**: Uses SQL conditions from ability rules for efficient database queries.
**性能说明**:利用权限规则生成SQL条件,实现高效的数据库查询。undefinedundefinedundefinedundefined<nav>
<%= link_to 'Posts', posts_path if can? :read, Post %>
<%= link_to 'New Post', new_post_path if can? :create, Post %>
<%= link_to 'Admin', admin_path if can? :manage, :all %>
</nav><nav>
<%= link_to 'Posts', posts_path if can? :read, Post %>
<%= link_to 'New Post', new_post_path if can? :create, Post %>
<%= link_to 'Admin', admin_path if can? :manage, :all %>
</nav>undefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedrescue_from CanCan::AccessDenied do |exception|
redirect_to root_path, alert: "Access denied: #{exception.message}"
endrescue_from CanCan::AccessDenied do |exception|
redirect_to root_path, alert: "Access denied: #{exception.message}"
endundefinedundefinedif user.admin?
can :manage, :all
elsif user.moderator?
can :manage, Post
can :manage, Comment
can :read, User
elsif user.user?
can :read, :all
can :create, Post
can :manage, Post, user_id: user.id
can :manage, Comment, user_id: user.id
else
can :read, Post, published: true
endundefinedif user.admin?
can :manage, :all
elsif user.moderator?
can :manage, Post
can :manage, Comment
can :read, User
elsif user.user?
can :read, :all
can :create, Post
can :manage, Post, user_id: user.id
can :manage, Comment, user_id: user.id
else
can :read, Post, published: true
endundefinedclass Ability
include CanCan::Ability
def initialize(user)
return unless user.present?
# User can manage resources in their organization
can :manage, Post, organization_id: user.organization_id
can :manage, Comment, post: { organization_id: user.organization_id }
# Admin can manage organization settings
can :manage, Organization, id: user.organization_id if user.admin?
end
endclass Ability
include CanCan::Ability
def initialize(user)
return unless user.present?
# User can manage resources in their organization
can :manage, Post, organization_id: user.organization_id
can :manage, Comment, post: { organization_id: user.organization_id }
# Admin can manage organization settings
can :manage, Organization, id: user.organization_id if user.admin?
end
endclass Ability
include CanCan::Ability
def initialize(user)
return unless user.present?
# Can edit posts within 1 hour of creation
can :update, Post do |post|
post.user_id == user.id && post.created_at > 1.hour.ago
end
# Can read posts after publication date
can :read, Post, ["published_at <= ?", Time.current]
end
endclass Ability
include CanCan::Ability
def initialize(user)
return unless user.present?
# Can edit posts within 1 hour of creation
can :update, Post do |post|
post.user_id == user.id && post.created_at > 1.hour.ago
end
# Can read posts after publication date
can :read, Post, ["published_at <= ?", Time.current]
end
endclass Ability
include CanCan::Ability
def initialize(user)
return unless user.present?
# Users can update specific attributes of their own posts
can [:update], Post, user_id: user.id
# Only admins can change published status
cannot :update, Post, :published unless user.admin?
# Users can update their profile but not role
can :update, User, id: user.id
cannot :update, User, :role
end
endclass Ability
include CanCan::Ability
def initialize(user)
return unless user.present?
# Users can update specific attributes of their own posts
can [:update], Post, user_id: user.id
# Only admins can change published status
cannot :update, Post, :published unless user.admin?
# Users can update their profile but not role
can :update, User, id: user.id
cannot :update, User, :role
end
endundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedit { is_expected.to be_able_to(:read, Post.new(published: true)) }
it { is_expected.not_to be_able_to(:create, Post) }
it { is_expected.not_to be_able_to(:update, Post) }it { is_expected.to be_able_to(:read, Post) }
it { is_expected.to be_able_to(:create, Post) }
it { is_expected.to be_able_to(:update, own_post) }
it { is_expected.not_to be_able_to(:update, other_post) }
it { is_expected.to be_able_to(:destroy, own_post) }
it { is_expected.not_to be_able_to(:destroy, other_post) }it { is_expected.to be_able_to(:manage, :all) }undefinedit { is_expected.to be_able_to(:read, Post.new(published: true)) }
it { is_expected.not_to be_able_to(:create, Post) }
it { is_expected.not_to be_able_to(:update, Post) }it { is_expected.to be_able_to(:read, Post) }
it { is_expected.to be_able_to(:create, Post) }
it { is_expected.to be_able_to(:update, own_post) }
it { is_expected.not_to be_able_to(:update, other_post) }
it { is_expected.to be_able_to(:destroy, own_post) }
it { is_expected.not_to be_able_to(:destroy, other_post) }it { is_expected.to be_able_to(:manage, :all) }undefinedundefinedundefinedcontext 'when editing other user post' do
let(:other_post) { create(:post, user: other_user) }
it 'denies access' do
expect {
get :edit, params: { id: other_post.id }
}.to raise_error(CanCan::AccessDenied)
end
endundefinedcontext 'when editing other user post' do
let(:other_post) { create(:post, user: other_user) }
it 'denies access' do
expect {
get :edit, params: { id: other_post.id }
}.to raise_error(CanCan::AccessDenied)
end
endundefinedRSpec.describe 'Post access', type: :model do
let(:user) { create(:user) }
let(:admin) { create(:user, admin: true) }
let!(:published_post) { create(:post, published: true) }
let!(:draft_post) { create(:post, published: false, user: user) }
let!(:other_draft) { create(:post, published: false) }
it 'returns correct posts for user' do
ability = Ability.new(user)
accessible = Post.accessible_by(ability)
expect(accessible).to include(published_post, draft_post)
expect(accessible).not_to include(other_draft)
end
it 'returns all posts for admin' do
ability = Ability.new(admin)
accessible = Post.accessible_by(ability)
expect(accessible).to include(published_post, draft_post, other_draft)
end
endRSpec.describe 'Post access', type: :model do
let(:user) { create(:user) }
let(:admin) { create(:user, admin: true) }
let!(:published_post) { create(:post, published: true) }
let!(:draft_post) { create(:post, published: false, user: user) }
let!(:other_draft) { create(:post, published: false) }
it 'returns correct posts for user' do
ability = Ability.new(user)
accessible = Post.accessible_by(ability)
expect(accessible).to include(published_post, draft_post)
expect(accessible).not_to include(other_draft)
end
it 'returns all posts for admin' do
ability = Ability.new(admin)
accessible = Post.accessible_by(ability)
expect(accessible).to include(published_post, draft_post, other_draft)
end
endundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefined