专家的类别政策规范问题 gem

problems for Category Policy Spec with pundit gem

所以我通过分类将类别和帖子关联起来。 我正在尝试限制专家 gem 的访问权限,并使用 RSpec 进行测试以按类别显示帖子。因为有了这个协会,我有类似的东西: c = Category.first c.posts

我按类别显示帖子。

我需要一些帮助。

我的categories_controller.rb

class CategoriesController < ApplicationController
  before_action :set_category, only: [:show]

  def show
    authorize @category, :show?
  end

  private

  def set_category
    @category = Category.find(params[:id])
  end
end

category.rb

class Category < ActiveRecord::Base
  has_many :categorizations, dependent: :destroy
  has_many :posts, through: :categorizations

  validates :name,
                  presence: true,
                  length: { minimum: 3, maximum: 30 },
                  uniqueness: true
end

app/views/categories/show.html.slim

= title("Category - #{@category.name}")
#category.text-center
  h1 Category: <small>#{@category.name}</small>

  - if @category.posts
    #category.posts
      - @category.posts.each do |post|
        .row.col-md-12
          .caption
            h2 = link_to post.title, post
            p = link_to post.subtitle, post
            small = "by : #{post.author}"
          hr

routes.rb

Rails.application.routes.draw do

  namespace :admin do
    root 'application#index'

    resources :posts, only: [:new, :create, :destroy]
    resources :categories

    resources :users do
      member do
        patch :archive
      end
    end
  end

  devise_for :users

  root "posts#index"

  resources :posts, only: [:index, :show, :edit, :update]
  resources :categories, only: [:show]
end

category_policy.rb

class CategoryPolicy < ApplicationPolicy
  class Scope < Scope
    def resolve
      resolve
    end
  end

  def show?
    user.try(:admin?) || record.post.has_member?(user)
  end
end

category_policy_spec.rb

require 'rails_helper'

RSpec.describe CategoryPolicy do
  context "permissions" do
    subject        { CategoryPolicy.new(user, category) }
    let(:user)     { create(:user) }
    let(:post)     { create(:post) }
    let(:category) { create(:category) }

    context "for anonymous users" do
      let(:user) { nil }

      it { should_not permit_action :show }
    end

    context "for viewers of the post" do
      before { assign_role!(user, :viewer, post) }

      it { should permit_action :show }
    end

    context "for editors of the post" do
      before { assign_role!(user, :editor, post) }

      it { should permit_action :show }
    end

    context "for managers of the post" do
      before { assign_role!(user, :manager, post) }

      it { should permit_action :show }
    end

    context "for managers of other posts" do
      before do
         assign_role!(user, :manager, create(:post))
      end

      it { should_not permit_action :show }
    end

    context "for administrators" do
      let(:user) { create(:user, :admin) }

      it  { should permit_action :show }
    end
  end
end

我正在使用这个匹配器。 pundit_matcher.rb

RSpec::Matchers.define :permit_action do |action|
  match do |policy|
    policy.public_send("#{action}?")
  end

  failure_message do |policy|
    "#{policy.class} does not allow #{policy.user || "nil"} to " +
      "perform :#{action}? on #{policy.record}."
  end

  failure_message_when_negated do |policy|
    "#{policy.class} does not forbid #{policy.user || "nil"} from " +
      "performing :#{action}? on #{policy.record}."
  end
end

post.rb

class Post < ActiveRecord::Base
  belongs_to :author, class_name: "User"
  has_many :roles, dependent: :delete_all
  has_many :categorizations, dependent: :destroy
  has_many :categories, through: :categorizations

  mount_base64_uploader :attachment, AttachmentUploader

  validates :title,
              presence: true,
              length: { minimum: 10, maximum: 100 },
              uniqueness: true
  validates :subtitle,
              length: { maximum: 100 }
  validates :content,
              presence: true,
              length: { minimum: 30 }
  validates :attachment, file_size: { less_than: 1.megabytes }


  def has_member?(user)
    roles.exists?(user_id: user)
  end

  [:manager, :editor, :viewer].each do |role|
    define_method "has_#{role}?" do |user|
      roles.exists?(user_id: user, role: role)
    end
  end

end

roler.rb

class Role < ActiveRecord::Base
  belongs_to :user
  belongs_to :post

  def self.available_roles
    %w(manager editor viewer)
  end
end

当我尝试 运行 时:

rspec spec/policies/category_policy_spec.rb

我收到这个错误:

Failure/Error: user.try(:admin?) || record.post.has_member?(user)

     NoMethodError:
       undefined method `post' for #<Category:0x007fc61bfdbf40>
       Did you mean?  posts

可以在节目中按类别显示此帖子,还是我需要切换到索引?

如错误所述,您的类别模型没有 post 方法,它只有 posts。这是因为类别 has_many posts。因为您的类别策略中的 record.post.has_member?(user) 没有任何意义(record 是类别实例)。由于类别似乎与用户没有直接关系,并且您的角色与用户和 post 相关联。

我不清楚你的类别政策的实际目的是什么,除非它只允许用户在已经有 post 使用该类别的情况下查看类别?如果是这种情况,那么您需要更改策略以实际检查其中是否存在。