0

I am creating a Single Table Inheritance model to build a comment thread and I am getting a confusing routing error

I have set up my Model

class Question < ApplicationRecord
  has_many :answers, class_name: 'Questions::Answer'
end

class Answer < ApplicationRecord
  has_many :answers, class_name: 'Answers::Answer'
end

with associated sub classes

module Questions
  class Answer < ::Answer
    belongs_to :question
    validates :body, presence: true
    validates :question, presence: true
  end
end

module Answers
  class Answer < ::Answer
    belongs_to :answer
    has_one :question, through: :answer
    validates :body, presence: true
    validates :answer, presence: true
  end
end

Routes

resources :questions do 
    resources :answers, shallow: true 
end

In my view, I render answers and a form to add an answer

<%= render @answers %></br>
<%= render "answers/form" %>

Which takes the following instances from my Question controller

 def show
    @answer = @question.answers.new
    @answers = @question.answers.page(params[:page]).per(5)
 end

However, this gives me an undefined method error: undefined method `questions_answers_path'

In my routes, indeed the only paths are

question_answers     GET    /questions/:question_id/answers(.:format)       answers#index
                     POST   /questions/:question_id/answers(.:format)       answers#create
new_question_answer  GET    /questions/:question_id/answers/new(.:format)   answers#new
edit_answer          GET    /answers/:id/edit(.:format)                     answers#edit
answer               GET    /answers/:id(.:format)                          answers#show         
                     PATCH  /answers/:id(.:format)                          answers#update       
                     PUT    /answers/:id(.:format)                          answers#update       
                     DELETE /answers/:id(.:format)                          answers#destroy

The question then is, why is it looking for the plural questions_answers_path, rather than question_answers_path.

The form is relatively standard:

<%= simple_form_for(@answer) do |f| %>
  <%= f.error_notification %>
  <%= f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present? %>

  <div class="form-inputs">
  <%= f.input :body %>
  </div>

  <div class="form-actions">
    <%= f.button :submit %>
  </div>
<% end %>

When I force the path by using <%= simple_form_for @answer, url: question_answers_path(@question) do |f| %> I get an error trying to submit the form. Body can't be blank

Any ideas on what is wrong with my code?

For completeness: Answers Controller

class AnswersController < ApplicationController
  before_action :set_answer, only: [:edit, :update, :destroy]
  before_action :set_question

  def create
    @answer = @question.answers.build(answer_params)

    respond_to do |format|
      if @answer.save
        format.html { redirect_to question_path(@question) }
        format.json { render :show, status: :created, location: @answer }
      else
        format.html { render :new }
        format.json { render json: @answer.errors, status: :unprocessable_entity }
      end
    end
  end

  def update
    authorize @answer
    respond_to do |format|
      if @answer.update(answer_params)
        format.html { redirect_to question_answers_path(@question), notice: 'Answer was successfully updated.' }
        format.json { render :show, status: :ok, location: @answer }
      else
        format.html { render :edit }
        format.json { render json: @answer.errors, status: :unprocessable_entity }
      end
    end
  end

  def destroy
    authorize @answer
    @answer = Answers.find(params[:id])
    @answer.discard
    respond_to do |format|
      format.html { redirect_to question_answers_path(@question), notice: 'Answer was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    def set_answer
      @answer = Answer.find(params[:id])
    end

    def answer_params
      params.fetch(:answer, {}).permit(:body, :type).merge(user_id: current_user.id, question_id: @question.id)
    end

    def set_question
      @question = Question.find(params[:question_id])
    end

end

Oats
  • 149
  • 3
  • 8
  • The reason why you have to give the explicit path is obvious: because you build an answer of class `Questions::Answer`, and the `simple_form_for` can only derive the path from the class of the form object. But this is an unorthodox solution imho to solve the threaded answers problem. Why do you solve it this way instead of using a self-referential link to a parent? – nathanvda Jan 05 '20 at 17:22
  • I initially tried the self-referential link to a parent, but was unable to get the answer to render in the correct position below the specific answer. I asked for help on StackOverflow and was recommended to remodel the problem using Self Table Inheritance. After doing some research it seemed to be a better fit, but as you can see i'm running into some problems. Do you know why the form validation throws an error even after I change the path? – Oats Jan 05 '20 at 17:37

0 Answers0