在CanCanCan规则中通过自引用关联进行过滤

时间:2017-12-02 18:48:07

标签: ruby-on-rails cancancan

在我的项目中,我有一个Post类,可以是对self-join的其他帖子的评论。除了其他规则,我想启用属于“已发布”帖子的帖子作为评论

我使用以下宝石:

gem 'rails', '5.0.6'
gem 'cancancan', '2.1.2'

以下是模型和能力等级

class Post < ActiveRecord::Base
  belongs_to :user
  belongs_to :parent, class_name: 'Post', optional: true
  has_many :comments, class_name: 'Post', foreign_key: 'parent_id', dependent: :destroy
end

class User < ActiveRecord::Base
  has_many :posts
end

class Ability
  include CanCan::Ability

  def initialize(user)
    can :read, Post, parent: { status: %w(published), user: { id: user.id } }
  end
end

我写了一些RSpec测试,所有测试都应该根据上面的规则传递。

RSpec.describe Ability do
  subject(:ability){ Ability.new(user) }

  let!(:user) { User.create }
  let!(:commenter) { User.create }
  let!(:post) { Post.create(user: user, parent: nil, status: 'published') }
  let!(:comment) { Post.create(user: commenter, parent: post) }

  # for individual objects it works
  it { is_expected.not_to be_able_to :read, post } # pass
  it { is_expected.to be_able_to :read, comment } # pass

  # for accessible by query it fails
  it { expect(Post.accessible_by(ability)).not_to include post } # pass
  it { expect(Post.accessible_by(ability)).to include comment } # fail
end

当我运行RSpec测试时,最后一个测试失败。如果检查SQL日志,可以看到它创建了正确的JOINS,但它有一个错误的WHERE语句。

SELECT (...)
FROM "posts"
LEFT OUTER JOIN "posts" "parents_posts" ON "parents_posts"."id" = "posts"."parent_id"
LEFT OUTER JOIN "users" ON "users"."id" = "parents_posts"."user_id" 
WHERE "posts"."status" = 'published' 
AND "users"."id" = ?
你可以帮帮我吗?这是CanCanCan中的错误还是我错误地使用了hash syntax

1 个答案:

答案 0 :(得分:0)

好的,我不知道你是否可以解决这个问题,但我会尽力帮助你。

def initialize(user)
    can :read, Post, id: Post.where(parent: { status: 'published', user: { id: user.id }) }
end

试试这个,然后告诉我给你的回报。