for example, there's a Question
model that has_many :answers
I'd like to show a form for new answer on the questions#show
( just like stackoverflow does )
routes would be something like:
resources :questions do
resources :answers
end
What is the best way to show the errors for an invalid record under these circumstances?
The problem is that I can't render
an action I need from within AnswersController
( since it would be questions#show
), the only way seem to be redirect_to
and store errors in flash
hash.
It just looks like a pretty much common scenario, I believe there should be some better way
This may be one of a few cases where it's actually justified to add a new resourceful member route to your QuestionsController
:
resources :questions do
post 'answer', :on => :member
end
which would recognize question/:id/answer
with a POST request routed to questions#answer
, allowing you keep all the logic in one controller:
class QuestionsController < ApplicationController
...
def show
@question = Question.find(params[:id])
end
def answer
@question = Question.find(params[:id])
@answer = @question.answers.build(params[:question][:answer])
if @answer.save
# show question with newly posted answer at url /question/:id
redirect_to @question
else
# show question with invalid editable answer at url /question/:id/answer
render 'show'
end
end
...
end
Explanation: In my opinion, the decision to handle the logic in one controller as opposed to two comes down to what you consider to be the resource of interest. Normally, you would consider each model to represent a distinct resource and thus create a separate controller to handle actions related to each resource. However, when there are multiple deeply coupled models for which multiple actions (e.g. show
, new
, create
) are handled in a single view, it might be cleaner to think of the models as forming a single resource.
In this example, I think of the resource as a collective one consisting of both the question and its answers. Since this collective resource is uniquely identified by the question itself, I would let the question controller handle it. The show
action in the questions controller already involves retrieving the collective question-answers resource, so you might think of the answer
action (and potentially unanswer
and reanswer
actions) as the analogue of update
to that collective resource.
Thinking of the resources this way is largely a matter of design preference, and there will be trade-offs depending on the requirements.