ruby-on-railsruby-on-rails-6cancancan

Cancancan - define :create with association


I have the following situation in my Ruby on Rails application:

I have a blog with posts. Each post can have 1 to n authors, and each post is associated with several comments:

class Post < ApplicationRecord
    has_many :comments, dependent: :destroy
    has_many :authors

class Comment < ApplicationRecord
    belongs_to :post

I am using CanCanCan for authorization. Currently everyone is able to create comments on a post. I want to change this by introducing a lock_comments-attribute on my post model, and changing the authorization accordingly, so that it functions as follows:

Basically the authors should be able to disable comments on their articles, but they should still be able to write comments on their own articles, even if the comments are disabled for others.

I am a bit at a loss here and could not find anything in the documentation. How do I have to define my Ability for this to work?


Solution

  • I don't think you can do this in Ability because at the time you're trying to access create you don't know what the parent post is. You COULD do this if create_comment was a PostsController method...

    can :create_comment, Post do |post|
      !post.lock_comments || user.in?(post.authors)
    end
    

    But if it's create in a CommentsController you'd need to do this with a before_action

    class CommentsController < ApplicationController
    
      before_action :create_allowed, only: [:create]
    
      private
    
      def create_allowed
        post = Post.find(params[:comment][:post_id])
        return if post && (!post.lock_comments || current_user.in?(post.authors))
        flash[:error] = 'You are not allowed to do this'
        redirect_to root_path
      end
    end