开发者

Editing multiple nested records simultaneously in Rails

开发者 https://www.devze.com 2022-12-20 21:58 出处:网络
I\'m creating a simple quiz application where a question can have multiple answers. To improve the usability of my app, I want users to be able to edit ALL the answers for a given question in the same

I'm creating a simple quiz application where a question can have multiple answers. To improve the usability of my app, I want users to be able to edit ALL the answers for a given question in the same form:

I found this great Railscast/Asciicast episode which does almost EXACTLY what I want to do

http://asciicasts.com/episodes/198-edit-multiple-individually

However, there's a catch. My answers model is nested within questions like so:

  map.resources 开发者_开发技巧:answers, :has_one => :question

  map.resources :questions, :has_many => :answers

So when it comes time to define the route and form tag I come a bit unstuck... The tutorial suggests creating 2 new controller methods and defining the routes and form tags as follows:

map.resources :products, :collection => { :edit_individual => :post, :update_individual => :put } 

<% form_tag edit_individual_products_path do %>  

But this doesn't work in my case as Answers are dependent on Questions... Any ideas on how to translate this tutorial for my nested models?


Working with nested routes looks pretty from some point of view, but always become a bit tricky. In order for this to work you will have to

  1. Fix the routes definition
  2. Adapt the URL generators in all views (like form_for or answers_path)

Routes

First things first: Specifying associations within the routes won't allow you to add custom routes to the second class. I would do something like this:

map.resources :questions do |question|
  question.resources :answers, :collection => {
     :edit_individual => :post, 
     :update_individual => :put }
end

Views

It's really important to notice the change in URL generators:

  • edit_answer_path(@answer) => edit_question_answer_path(@question, @answer)
  • edit_individual_answer_path(@answer) => edit_individual_question_answer_path(@question, @answer)

I've made a fast adaptation of the Railscasts views:

<!-- views/answers/index.html.erb -->
<% form_tag edit_individual_question_answer_path(@question) do %>
  <table>
    <tr>
      <th></th>
      <th>Name</th>
      <th>Value</th>
    </tr>
  <% for answer in @answers %>
    <tr>
      <td><%= check_box_tag "answer_id_ids[]", answer.id %></td>
      <td><%=h answer.name %></td>
      <td><%=h answer.value %></td>
      <td><%= link_to "Edit", edit_question_answer_path(@question, answer) %></td>
      <td><%= link_to "Destroy", question_answer_path(@question, answer), :confirm => 'Are you sure?', :method => :delete %></td>
    </tr>
  <% end %>
  </table>
  <p>
    <%= select_tag :field, options_for_select([["All Fields", ""], ["Name", "name"], ["Value", "value"]]) %>
    <%= submit_tag "Edit Checked" %>
  </p>
<% end %>

<!-- views/answers/edit_individual.html.erb -->
<% form_tag update_individual_question_answers_path, :method => :put do %>
  <% for answer in @answers %>
    <% fields_for "answers[]", answer do |f| %>
      <h2><%=h answer.name %></h2>
      <%= render "fields", :f => f %>
    <% end %>
  <% end %>
  <p><%= submit_tag "Submit" %></p>
<% end %>

Extra

As you may have seen, you will require the variable @question within your views, so I would recommend you to have a before_filter in your AnswersController that fetches the question object:

AnswersController
  before_filer :get_question

  [...]

  private
  def get_question
    # @question will be required by all views
    @question = Question.find(params[:question_id])
  end
end

Enjoy your nested routes!!

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号