Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple forms for the same model in a single page

On the front page of my rap lyrics explanation site, there's a place where users can try explaining a challenging line:

alt text http://dl.dropbox.com/u/2792776/screenshots/2010-02-06_1620.png

Here's the partial I use to generate this:

<div class="stand_alone annotation" data-id="<%= annotation.id %>">
  <%= song_link(annotation.song, :class => :title) %>

  <span class="needs_exegesis"><%= annotation.referent.strip.gsub(/\n/, "\n <br />") %></span>

  <% form_for Feedback.new(:annotation_id => annotation.id, :created_by_id => current_user.try(:id), :email_address => current_user.try(:email)), :url => feedback_index_path, :live_validations => true do |f| %>
    <%= f.hidden_field :annotation_id %>
    <%= f.hidden_field :created_by_id %>
    <p style="margin-top: 1em">
        <%= f.text_area :body, :rows => 4, :style => 'width:96%', :example_text => "Enter your explanation" %>
    </p>
    <p>
      <% if current_user %>
        <%= f.hidden_field :email_address %>
      <% else %>
        <%= f.text_field :email_address, :example_text => "Your email address" %>
      <% end %>
      <%= f.submit "Submit", :class => :button, :style => 'margin-left: .1em;' %>
    </p>
  <% end %>
</div>

However, putting more than one of these on a single page is problematic because Rails automatically gives each form an ID of new_feedback, and each field an ID like feedback_body (leading to name collisions)

Obviously I could add something like :id => '' to the form and all its fields, but this seems a tad repetitive. What's the best way to do this?

like image 274
Tom Lehman Avatar asked Feb 06 '10 21:02

Tom Lehman


2 Answers

If you don't want to change your input names or your model structure, you can use the id option to make your form ID unique and the namespace option to make your input IDs unique:

<%= form_for Feedback.new(...), 
    id: "annotation_#{annotation.id}_feedback"
    namespace: "annotation_#{annotation.id}" do |f| %>

That way our form ID is unique, i.e. annotation_2_feedback and this will also add a prefix, e.g. annotation_2_, to every input created through f.

like image 169
Daniel Rikowski Avatar answered Sep 22 '22 06:09

Daniel Rikowski


Did you consider nested_attributes for rails models? Instead of having multiple new feedback forms where each is tied to an annotation, you could have multiple edit annotation forms where each annotation includes fields for a new feedback. The id's of the generated forms would include the annotations id such as edit_annotation_16.

The annotation model would have a relationship to its feedbacks and will also accept nested attributes for them.

class Annotation < ActiveRecord::Base
  has_many :feedbacks
  accepts_nested_attributes_for :feedbacks
end

class Feedback < ActiveRecord::Base
  belongs_to :annotation
end

You could then add as many forms as you want, one for each annotation. For example, this is what I tried:

<% form_for @a do |form| %>
    Lyrics: <br />
    <%= form.text_field :lyrics %><br />
    <% form.fields_for :feedbacks do |feedback| %>
        Feedback: <br/>
        <%= feedback.text_field :response %><br />
    <% end %>
    <%= form.submit "Submit" %>
<% end %>

<% form_for @b do |form| %>
    Lyrics: <br />
    <%= form.text_field :lyrics %><br />
    <% form.fields_for :feedbacks do |feedback| %>
        Feedback: <br/>
        <%= feedback.text_field :response %><br />
    <% end %>
    <%= form.submit "Submit" %>
<% end %>

And the quick and dirty controller for the above edit view:

class AnnotationsController < ApplicationController
  def edit
    @a = Annotation.find(1)
    @a.feedbacks.build
    @b = Annotation.find(2)
    @b.feedbacks.build
  end

  def update
    @annotation = Annotation.find(params[:id])
    @annotation.update_attributes(params[:annotation])
    @annotation.save!
    render :index
  end
end
like image 20
Anurag Avatar answered Sep 18 '22 06:09

Anurag