Sensanaty
Sensanaty

Reputation: 1106

Rails run validation for a specific controller method

Running Rails 5.2.3 in API-only mode.

I have a Questions model, which has a disabled flag that I update via a PATCH. The specific method I'm calling is namespaced like this: v1/custom_questions/questions#disable. My Questions model also has another boolean, standard.

Now in the app, I have 5 questions that are standard, AKA their standard field is true. I also have some functionality where I let users create their own Questions, and these Questions all have standard: false by default. I want to let users disable their custom questions, but I don't want to allow them to disable the standard questions.

How can I set up validation that runs whenever the API receives the PATCH /disable request that checks whether the question supplied is a standard one? I know that I can use validates :validation_method, on: :create, but I'm not sure how to write this out so that it triggers when I call the disable method namespaced under V1::CustomQuestions::QuestionsController.

I currently have this logic in the controller, but I'd rather move this to a model validation so that @question.errors gets populated if the ID supplied belongs to a standard question.

#questions_controller

class QuestionsController < ApplicationController

  def disable
    @question = Question.find(params[:id])

    if @question.standard?
      return
    else
      @question.disabled = true
    end

    if @question.save
      render json: @question
    else
      render json: @question.errors, status: :bad_request
    end
  end

end

I've tried doing the below, however the @question.save check seems to overwrite any errors I manually create.

if @question.standard?
      @question.errors[:standard] << "Cannot deactivate a standard question"
    else
      @question.deleted = true
    end

Upvotes: 0

Views: 733

Answers (1)

Narendra
Narendra

Reputation: 382

The current structure is the culprit where you got into this situation. The responsibility of validation should be within the model and not outside it. Otherwise, one consumer (QuestionController in this case) may put some kind of validation and another one might skip it entirely.

You can try out the following snippet and see if this works for you.

class QuestionsController < ApplicationController

  def disable
    @question = Question.find(params[:id])

    @question.disabled = true

    if @question.save
      render json: @question
    else
      render json: @question.errors, status: :bad_request
    end
  end
end


class Question < ApplicationRecord
    validate :validate_disabled, on: update

    def validate_disabled
        if standard? && disabled
            question.errors.add(:disable, "You cannot disable a standard question")
        end
    end
end

Upvotes: 1

Related Questions