单个页面中同一模型的多个表单

时间:2010-02-06 21:39:28

标签: ruby-on-rails ruby forms

在我rap lyrics explanation site的首页上,有一个用户可以尝试解释具有挑战性的一行的地方:

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

以下是我用来生成此内容的部分内容:

<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>

但是,将多个这些放在一个页面上是有问题的,因为Rails会自动为每个表单提供new_feedback的ID,每个字段的ID为feedback_body(导致名称冲突)< / p>

显然,我可以在表单及其所有字段中添加:id => ''之类的内容,但这似乎有点重复。最好的方法是什么?

5 个答案:

答案 0 :(得分:10)

如果您不想更改输入名称或模型结构,可以使用id选项使表单ID唯一,并使用namespace选项使输入ID唯一:

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

这样我们的表单ID就是唯一的,即annotation_2_feedback,这也会添加一个前缀,例如annotation_2_,通过f创建的每个输入。

答案 1 :(得分:6)

您是否考虑过rails模型的nested_attributes?您可以拥有多个new注释表单,其中每个注释都包含新反馈的字段,而不是具有多个edit反馈表单,其中每个表单都与注释相关联。生成的表单的ID将包含注释ID,例如edit_annotation_16

注释模型与其反馈有关系,也会接受它们的嵌套属性。

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

class Feedback < ActiveRecord::Base
  belongs_to :annotation
end

然后,您可以根据需要添加任意数量的表单,每个表单一个。例如,这就是我尝试过的:

<% 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 %>

以上编辑视图的快速且脏的控制器:

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

答案 2 :(得分:3)

我在目前正在处理的网站上遇到了同样的问题,并使用了您在底部提到的解决方案。如果以编程方式生成ID并将整个表单放在一个部分中,则不重复。例如,在我的网站上,每页有多个“条目”,每个条目有两个投票表单,一个投票,另一个投票。每个条目的记录ID都附加到其投票表单的DOM ID以使其唯一,就像这样(只显示投票按钮,投票按钮类似):

<% form_for [entry, Vote.new], :html => { :id => 'new_up_vote_' + entry.id.to_s } do |f| -%>
  <%= f.hidden_field :up_vote, :value => 1, :id => 'vote_up_vote_' + entry.id.to_s %>
  <%= image_submit_tag('/images/icon_vote_up.png', :id => 'vote_up_vote_submit' + entry.id.to_s, :class => 'vote-button vote-up-button') %>
<% end -%>

答案 3 :(得分:2)

我也有同样的问题,但想要一个比每个字段添加ID更具扩展性的解决方案。因为我们已经在使用form_for ... | f |表示技巧是更改模型的名称,并获得新的HTML ID前缀。

使用此方法的变体:http://www.dzone.com/snippets/create-classes-runtime(我删除了&amp; block stuff)

我创建了一个新模型,它是我希望在同一页面上使用第二个表单的模型的精确副本。然后使用该新模型呈现新表单。

如果第一个表单正在使用

@address = Address.new

然后

create_class('AddressNew', Address)
@address_new = AddressNew.new

对于同一模型的第二种形式,您的ID前缀将是“address_new_”而不是“address_”。当您阅读表格参数时,您可以创建一个地址模型来将值放入。

答案 4 :(得分:1)

对于那些在寻找Rails 3.2应用程序解决方案的绊脚石,请转而看看这个问题:

Rails: Using form_for multiple times (DOM ids)