ruby-on-railscontrollercancanself-reference

Problem with role based authorization in rails self reference table association


I have a single self reference table for product's question and answers section named question_and_answers with columns: id, parent_id, text_field, user_id and product_id. Question has no parent_id and answers have parent_id of question. User have two roles of vendor and customer.

How do I code the create action for both question and answer in same controller action if user with role customer can create question with nil parent_id and user with role vendor can create answer with parent_id of the question's id. I am stuck on how to allow customers to create only questions and vendors to create only answers. I am using CanCan for role based authoriazation.

My association is like this:

QuestionAndAnswer
belongs_to product, belongs_to user
has_many parent, class_name: QuestionAndAnswer, foreign_key: parent_id

User
has_many question_and_answers

Product 
has_many question_and_answers

My controller is like this right now

class QuestionAndAnswersController < Api::BaseController
def create
   @thread = QuestionAndAnswer.new(thread_params)
   if @thread.save
     render json: @thread, status: :created
   else
     render status: 422 , json: {
     success: false,
     message: "Couldn't create thread"
   }
   end
end

def permitted_params
   [:parent_id, :textfield, :product_id, :user_id]
end

def thread_params
   params.permit(permitted_params)        
end
end

Should i add something in my controller action?? I am blank right now


Solution

  • One way of doing this is creating a method to check if the params are valid or not according to the user role,

    def valid_params?
      has_parent = permitted_params[:parent_id].present?
    
      return false if current_user.vendor? && !has_parent
      return false if current_user.customer? && has_parent
    
      return true
    end
    

    Then use this in create action

    def create
       @thread = QuestionAndAnswer.new(thread_params)
    
       if valid_params? && @thread.save
         ...
       else
         ...
       end
    end
    

    Ofcourse you need to replace current_user.vendor? or current_user.customer? with equivalent method of checking provided by cancan.

    Hope that answers your question!