Ruby on rails CanCanCan不允许访问返回所有记录的端点

Ruby on rails CanCanCan不允许访问返回所有记录的端点,ruby-on-rails,cancancan,rolify,Ruby On Rails,Cancancan,Rolify,我正在尝试为我在Rails中构建的API配置授权。授权似乎有效,但在返回资源所有记录的端点上无效。这些端点也恰好是在config/routes.rb中的资源块外部创建的(不确定这是否是正确的解释方法) 例如:当我转到以下端点时,如果有数据,我会得到200 HTTP响应;如果记录不存在,我会得到204 HTTP响应: http://localhost:3000/v1/resources/venues/zoom 但当我转到以下端点时,我得到一个授权错误: http://localhost:3000

我正在尝试为我在Rails中构建的API配置授权。授权似乎有效,但在返回资源所有记录的端点上无效。这些端点也恰好是在
config/routes.rb
中的资源块外部创建的(不确定这是否是正确的解释方法)

例如:当我转到以下端点时,如果有数据,我会得到200 HTTP响应;如果记录不存在,我会得到204 HTTP响应:

http://localhost:3000/v1/resources/venues/zoom
但当我转到以下端点时,我得到一个授权错误:

http://localhost:3000/v1/resources/venues/all
这是我的
config/routes.rb
文件:

Rails.application.routes.draw do
  # Private Messaging
  resources :conversations, only: [:index, :create]
  resources :messages, only: [:create]
  mount ActionCable.server => '/cable'

  # Admin
  mount RailsAdmin::Engine => '/admin', as: 'rails_admin'

  namespace :v1 do
    namespace :resources do
      # Users
      post '/users/:id/avatar/upload' => 'users#upload_avatar'
      patch '/users/:id/avatar/update' => 'users#update_avatar'
      put '/users/:id/avatar/update' => 'users#update_avatar'
      delete '/users/:id/avatar/delete' => 'users#delete_avatar'
      namespace :users do
        get ':id' => :show
      end

      # Venue Types
      get '/venue_types/all' => 'venue_types#all'
      post '/venues/:name/images/upload' => 'venues#upload_images'
      namespace :venue_types do
        get ':name' => :show
        patch ':name' => :update
        put ':name' => :update
        delete ':name' => :delete
        post 'new'
      end

      # Attributes
      get '/attribute_defaults/all' => 'attribute_defaults#all'
      namespace :attribute_defaults do
        get ':id' => :show
        patch ':id' => :update
        put ':id' => :update
        delete ':id' => :delete
        post 'new'
      end

      # Venues
      get '/venues/all' => 'venues#all'
      namespace :venues do
        get ':name' => :show
        patch ':name' => :update
        put ':name' => :update
        delete ':name' => :delete
        post 'new'
      end

      # Venue Attributes
      get '/venue_attributes/all' => 'venue_attributes#all'
      namespace :venue_attributes do
        get ':id' => :show
        patch ':id' => :update
        put ':id' => :update
        delete ':id' => :delete
        post 'new'
      end

      # Bids
      get '/bids/all' => 'bids#all'
      namespace :bids do
        get ':id' => :show
        patch ':id' => :update
        put ':id' => :update
        delete ':id' => :delete
        post 'new'
      end

      # Bookings
      get '/bookings/all' => 'bookings#all'
      namespace :bookings do
        get ':id' => :show
        patch ':id' => :update
        put ':id' => :update
        delete ':id' => :delete
        post 'new'
      end

      # Venue Ratings
      get '/venue_ratings/all' => 'venue_ratings#all'
      namespace :venue_ratings do
        get ':id' => :show
        patch ':id' => :update
        put ':id' => :update
        delete ':id' => :delete
        post 'new'
      end

      # User Ratings
      get '/user_ratings/all' => 'user_ratings#all'
      namespace :user_ratings do
        get ':id' => :show
        patch ':id' => :update
        put ':id' => :update
        delete ':id' => :delete
        post 'new'
      end
    end
  end

  # Auth
  devise_for :users,
    path: 'auth',
    path_names: {
     sign_in: 'login',
     sign_out: 'logout',
     registration: 'register'
    },
    controllers: {
      sessions: 'sessions',
      registrations: 'registrations',
      confirmations: 'confirmations'
    }
end
# frozen_string_literal: true

class Ability
  include CanCan::Ability

  def initialize(user)
    # Admin
    if user.present? && user.is_admin?
      can :manage, :all
    # Host
    elsif user.present? && user.is_host?
      can :manage, User, id: user.id
      can [:read, :write, :update], [Venue, VenueAttribute, Bid, UserRating, VenueRating]
      can [:read], User
      can :destroy, [Venue, VenueAttribute]
    # Guest
    elsif user.present? && user.is_guest?
      can :manage, User, id: user.id
      can [:write, :update], [Bid, VenueRating], id: user.id
      can [:write, :update], [UserRating], rated_by: user.id
      can :read, Bid, id: user.id
      can :read, [Venue, User, VenueRating, UserRating]
    # No role
    else
      can :read, [Venue, User, UserRating, VenueRating]
    end
  end
end
class V1::Resources::VenuesController < ActionController::API
  load_and_authorize_resource param_method: :venue_params
  respond_to :json
  before_action :authenticate_user!, except: [:all, :show]
  before_action :set_venue, except: [:all, :new]

  # GET /v1/resources/venues/all
  def all
    @venues = Venue.all.where(is_published: true, is_expired: false)
    if !@venues.empty?
      render json: @venues, methods: :image_urls, status: :ok
    else
      head :no_content
    end
  end

  # POST /v1/resources/venues/new
  def new
    @venue = Venue.new(venue_params)
    if @venue.save
      render json: @venue, status: :created
    else
      render json: @venue.errors, status: :unprocessable_entity
    end
  end

  # GET /v1/resources/venues/:name
  def show
    if @venue
      render json: @venue, methods: :image_urls, status: :ok
    else
      head :no_content
    end
  end

  # PATCH/PUT /v1/resources/venues/:name
  def update
    if @venue.update(venue_params)
      render json: @venue, status: :ok
    else
      render json: @venue.errors, status: :unprocessable_entity
    end
  end

  # DELETE /v1/resources/venues/:name
  def delete
    @venue.destroy
    head :no_content
  end

  # POST /v1/resources/venues/:name/images/upload
  def upload_images
    @venue.images.attach(params[:images])
    render json: @venue, methods: :image_urls, status: :ok
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_venue
      @venue = Venue.find_by(name: params[:name])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def venue_params
      params.require(:venue).permit(:name, :price, :minimum_bid, :is_published, :currency, :is_expired, :location, :venue_type_id, :user_id, images: [])
    end
end
这是我的
app/models/ability.rb
文件:

Rails.application.routes.draw do
  # Private Messaging
  resources :conversations, only: [:index, :create]
  resources :messages, only: [:create]
  mount ActionCable.server => '/cable'

  # Admin
  mount RailsAdmin::Engine => '/admin', as: 'rails_admin'

  namespace :v1 do
    namespace :resources do
      # Users
      post '/users/:id/avatar/upload' => 'users#upload_avatar'
      patch '/users/:id/avatar/update' => 'users#update_avatar'
      put '/users/:id/avatar/update' => 'users#update_avatar'
      delete '/users/:id/avatar/delete' => 'users#delete_avatar'
      namespace :users do
        get ':id' => :show
      end

      # Venue Types
      get '/venue_types/all' => 'venue_types#all'
      post '/venues/:name/images/upload' => 'venues#upload_images'
      namespace :venue_types do
        get ':name' => :show
        patch ':name' => :update
        put ':name' => :update
        delete ':name' => :delete
        post 'new'
      end

      # Attributes
      get '/attribute_defaults/all' => 'attribute_defaults#all'
      namespace :attribute_defaults do
        get ':id' => :show
        patch ':id' => :update
        put ':id' => :update
        delete ':id' => :delete
        post 'new'
      end

      # Venues
      get '/venues/all' => 'venues#all'
      namespace :venues do
        get ':name' => :show
        patch ':name' => :update
        put ':name' => :update
        delete ':name' => :delete
        post 'new'
      end

      # Venue Attributes
      get '/venue_attributes/all' => 'venue_attributes#all'
      namespace :venue_attributes do
        get ':id' => :show
        patch ':id' => :update
        put ':id' => :update
        delete ':id' => :delete
        post 'new'
      end

      # Bids
      get '/bids/all' => 'bids#all'
      namespace :bids do
        get ':id' => :show
        patch ':id' => :update
        put ':id' => :update
        delete ':id' => :delete
        post 'new'
      end

      # Bookings
      get '/bookings/all' => 'bookings#all'
      namespace :bookings do
        get ':id' => :show
        patch ':id' => :update
        put ':id' => :update
        delete ':id' => :delete
        post 'new'
      end

      # Venue Ratings
      get '/venue_ratings/all' => 'venue_ratings#all'
      namespace :venue_ratings do
        get ':id' => :show
        patch ':id' => :update
        put ':id' => :update
        delete ':id' => :delete
        post 'new'
      end

      # User Ratings
      get '/user_ratings/all' => 'user_ratings#all'
      namespace :user_ratings do
        get ':id' => :show
        patch ':id' => :update
        put ':id' => :update
        delete ':id' => :delete
        post 'new'
      end
    end
  end

  # Auth
  devise_for :users,
    path: 'auth',
    path_names: {
     sign_in: 'login',
     sign_out: 'logout',
     registration: 'register'
    },
    controllers: {
      sessions: 'sessions',
      registrations: 'registrations',
      confirmations: 'confirmations'
    }
end
# frozen_string_literal: true

class Ability
  include CanCan::Ability

  def initialize(user)
    # Admin
    if user.present? && user.is_admin?
      can :manage, :all
    # Host
    elsif user.present? && user.is_host?
      can :manage, User, id: user.id
      can [:read, :write, :update], [Venue, VenueAttribute, Bid, UserRating, VenueRating]
      can [:read], User
      can :destroy, [Venue, VenueAttribute]
    # Guest
    elsif user.present? && user.is_guest?
      can :manage, User, id: user.id
      can [:write, :update], [Bid, VenueRating], id: user.id
      can [:write, :update], [UserRating], rated_by: user.id
      can :read, Bid, id: user.id
      can :read, [Venue, User, VenueRating, UserRating]
    # No role
    else
      can :read, [Venue, User, UserRating, VenueRating]
    end
  end
end
class V1::Resources::VenuesController < ActionController::API
  load_and_authorize_resource param_method: :venue_params
  respond_to :json
  before_action :authenticate_user!, except: [:all, :show]
  before_action :set_venue, except: [:all, :new]

  # GET /v1/resources/venues/all
  def all
    @venues = Venue.all.where(is_published: true, is_expired: false)
    if !@venues.empty?
      render json: @venues, methods: :image_urls, status: :ok
    else
      head :no_content
    end
  end

  # POST /v1/resources/venues/new
  def new
    @venue = Venue.new(venue_params)
    if @venue.save
      render json: @venue, status: :created
    else
      render json: @venue.errors, status: :unprocessable_entity
    end
  end

  # GET /v1/resources/venues/:name
  def show
    if @venue
      render json: @venue, methods: :image_urls, status: :ok
    else
      head :no_content
    end
  end

  # PATCH/PUT /v1/resources/venues/:name
  def update
    if @venue.update(venue_params)
      render json: @venue, status: :ok
    else
      render json: @venue.errors, status: :unprocessable_entity
    end
  end

  # DELETE /v1/resources/venues/:name
  def delete
    @venue.destroy
    head :no_content
  end

  # POST /v1/resources/venues/:name/images/upload
  def upload_images
    @venue.images.attach(params[:images])
    render json: @venue, methods: :image_urls, status: :ok
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_venue
      @venue = Venue.find_by(name: params[:name])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def venue_params
      params.require(:venue).permit(:name, :price, :minimum_bid, :is_published, :currency, :is_expired, :location, :venue_type_id, :user_id, images: [])
    end
end
这是我的
app/controllers/v1/resources/vinces\u controller.rb
文件:

Rails.application.routes.draw do
  # Private Messaging
  resources :conversations, only: [:index, :create]
  resources :messages, only: [:create]
  mount ActionCable.server => '/cable'

  # Admin
  mount RailsAdmin::Engine => '/admin', as: 'rails_admin'

  namespace :v1 do
    namespace :resources do
      # Users
      post '/users/:id/avatar/upload' => 'users#upload_avatar'
      patch '/users/:id/avatar/update' => 'users#update_avatar'
      put '/users/:id/avatar/update' => 'users#update_avatar'
      delete '/users/:id/avatar/delete' => 'users#delete_avatar'
      namespace :users do
        get ':id' => :show
      end

      # Venue Types
      get '/venue_types/all' => 'venue_types#all'
      post '/venues/:name/images/upload' => 'venues#upload_images'
      namespace :venue_types do
        get ':name' => :show
        patch ':name' => :update
        put ':name' => :update
        delete ':name' => :delete
        post 'new'
      end

      # Attributes
      get '/attribute_defaults/all' => 'attribute_defaults#all'
      namespace :attribute_defaults do
        get ':id' => :show
        patch ':id' => :update
        put ':id' => :update
        delete ':id' => :delete
        post 'new'
      end

      # Venues
      get '/venues/all' => 'venues#all'
      namespace :venues do
        get ':name' => :show
        patch ':name' => :update
        put ':name' => :update
        delete ':name' => :delete
        post 'new'
      end

      # Venue Attributes
      get '/venue_attributes/all' => 'venue_attributes#all'
      namespace :venue_attributes do
        get ':id' => :show
        patch ':id' => :update
        put ':id' => :update
        delete ':id' => :delete
        post 'new'
      end

      # Bids
      get '/bids/all' => 'bids#all'
      namespace :bids do
        get ':id' => :show
        patch ':id' => :update
        put ':id' => :update
        delete ':id' => :delete
        post 'new'
      end

      # Bookings
      get '/bookings/all' => 'bookings#all'
      namespace :bookings do
        get ':id' => :show
        patch ':id' => :update
        put ':id' => :update
        delete ':id' => :delete
        post 'new'
      end

      # Venue Ratings
      get '/venue_ratings/all' => 'venue_ratings#all'
      namespace :venue_ratings do
        get ':id' => :show
        patch ':id' => :update
        put ':id' => :update
        delete ':id' => :delete
        post 'new'
      end

      # User Ratings
      get '/user_ratings/all' => 'user_ratings#all'
      namespace :user_ratings do
        get ':id' => :show
        patch ':id' => :update
        put ':id' => :update
        delete ':id' => :delete
        post 'new'
      end
    end
  end

  # Auth
  devise_for :users,
    path: 'auth',
    path_names: {
     sign_in: 'login',
     sign_out: 'logout',
     registration: 'register'
    },
    controllers: {
      sessions: 'sessions',
      registrations: 'registrations',
      confirmations: 'confirmations'
    }
end
# frozen_string_literal: true

class Ability
  include CanCan::Ability

  def initialize(user)
    # Admin
    if user.present? && user.is_admin?
      can :manage, :all
    # Host
    elsif user.present? && user.is_host?
      can :manage, User, id: user.id
      can [:read, :write, :update], [Venue, VenueAttribute, Bid, UserRating, VenueRating]
      can [:read], User
      can :destroy, [Venue, VenueAttribute]
    # Guest
    elsif user.present? && user.is_guest?
      can :manage, User, id: user.id
      can [:write, :update], [Bid, VenueRating], id: user.id
      can [:write, :update], [UserRating], rated_by: user.id
      can :read, Bid, id: user.id
      can :read, [Venue, User, VenueRating, UserRating]
    # No role
    else
      can :read, [Venue, User, UserRating, VenueRating]
    end
  end
end
class V1::Resources::VenuesController < ActionController::API
  load_and_authorize_resource param_method: :venue_params
  respond_to :json
  before_action :authenticate_user!, except: [:all, :show]
  before_action :set_venue, except: [:all, :new]

  # GET /v1/resources/venues/all
  def all
    @venues = Venue.all.where(is_published: true, is_expired: false)
    if !@venues.empty?
      render json: @venues, methods: :image_urls, status: :ok
    else
      head :no_content
    end
  end

  # POST /v1/resources/venues/new
  def new
    @venue = Venue.new(venue_params)
    if @venue.save
      render json: @venue, status: :created
    else
      render json: @venue.errors, status: :unprocessable_entity
    end
  end

  # GET /v1/resources/venues/:name
  def show
    if @venue
      render json: @venue, methods: :image_urls, status: :ok
    else
      head :no_content
    end
  end

  # PATCH/PUT /v1/resources/venues/:name
  def update
    if @venue.update(venue_params)
      render json: @venue, status: :ok
    else
      render json: @venue.errors, status: :unprocessable_entity
    end
  end

  # DELETE /v1/resources/venues/:name
  def delete
    @venue.destroy
    head :no_content
  end

  # POST /v1/resources/venues/:name/images/upload
  def upload_images
    @venue.images.attach(params[:images])
    render json: @venue, methods: :image_urls, status: :ok
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_venue
      @venue = Venue.find_by(name: params[:name])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def venue_params
      params.require(:venue).permit(:name, :price, :minimum_bid, :is_published, :currency, :is_expired, :location, :venue_type_id, :user_id, images: [])
    end
end
ClassV1::Resources::VenuesController
app/controllers/application\u controller.rb
文件中没有额外的代码


你知道我如何调试这个问题吗?另外,我如何授予未经身份验证的用户访问权限?我希望没有帐户的用户能够浏览场馆。

首先,将
加载和授权资源
更改为
授权资源
,因为您是手动加载的。在
all
操作中手动授权

class V1::Resources::VenuesController < ActionController::API
  authorize_resource param_method: :venue_params
  skip_authorize_resource only: :all
  respond_to :json
  before_action :authenticate_user!, except: [:all, :show]
  before_action :set_venue, except: [:all, :new]

  # GET /v1/resources/venues/all
  def all
    @venues = Venue.all.where(is_published: true, is_expired: false)
    authorize! :read, Venue
    if !@venues.empty?
      render json: @venues, methods: :image_urls, status: :ok
    else
      head :no_content
    end
  end
end

为了让它对未经身份验证的用户起作用,但是
:manage,:all
向未经身份验证的用户打开每个路由。我最后将我的加载和授权行更改为:
加载和授权资源参数method::场馆参数,除了:[:all]
,它似乎已经起作用,即使是未经身份验证的用户。@SteveTurczyn你说得对,这是一个例子,更新了answer@DerekC是的,如果您对
all
操作不需要任何授权,这是一个不错的选择。我仍然建议您将其更改为simple
authorize\u resource
以避免向数据库发出额外请求。当我更改为
authorize\u resource
时,我仍然在终端中看到相同的数据库查询。