简体   繁体   中英

rails respond_with associated record

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 (eg 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.

You can render questions#show from the AnswersController like this:

render :template => 'questions/show'

If you want to jump to a specific anchor on the page, you have to define that in your answer form:

<%= form_for(@answer, :url => question_answers_url(@question, :anchor => 'answer_form')) do |f| -%>

Have a partial which has the form which posts data to the answers_controller#create action.

So, in your questions#show page - show.html.erb, render a partial

<%= render :partial => "answers/answer_form" %>

In the _answer_form.html.erb, have a form which will post data to answers#create

<% form_for @answer do |f| %>
  # have a text area
<% end %>

As far as the flash is concerned

In the AsnwersController

def create
  @question = Question.find(params[:question_id])
  @answer = Answer.build(params)
  if @answer.save
    flash[:notice] = "Answer was posted successfully"  
  else
    flash[:error] = "There were a few errors please try again"  
  end
  redirect_to question_path(@question) 
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM