如何获得Rails构建和fields_for只创建一个新记录而不包括现有记录?

时间:2013-02-14 21:50:44

标签: ruby-on-rails

我正在使用buildfields_foraccepts_nested_attributes_for在与新注册相同的表单上创建新的注册说明(有许多注册说明)。大。

问题:在现有注册的编辑表单上,我想要创建另一个新注册注释,但我不希望看到每个现有注册注释的字段。

我有这个

class Registration < ActiveRecord::Base
  attr_accessible :foo, :bar, :registration_notes_attributes
  has_many :registration_notes
  accepts_nested_attributes_for :registration_notes
end

和这个

class RegistrationsController < ApplicationController
  def edit
    @registration = Registration.find(params[:id])
    @registration.registration_notes.build
  end
end

在视图中我这样做:

<%= form_for @registration do |r| %>
  <%= r.text_field :foo %>
  <%= r.text_field :bar %>
  <%= r.fields_for :registration_notes do |n| %>
    <%= n.text_area :content %>
  <% end %>
<% end %>

它正在为新的注册记录创建一个空白文本区域(好)该注册的每个现有注册记录(不,谢谢)。

有没有办法只为该注册创建一个新注释并将现有注释单独保留?

4 个答案:

答案 0 :(得分:72)

编辑:我之前的回答(见下文)让我烦恼,因为它不是很好(它仍然不必要地遍历所有其他registration_notes)。在阅读了API之后,获得OP所需行为的最佳方法是替换:

<%= r.fields_for :registration_notes do |n| %>

使用:

<%= r.fields_for :registration_notes, @registration.registration_notes.build do |n| %>

fields_for可选地接受第二个参数,该参数是要传递给构建器(see the API)的特定对象,该构建器是内联构建的。实际上,在控制器中创建和传递新音符可能更好,而不是在表单中传递(只是为了将逻辑移出视图)。


原始答案(我非常接近):

为了澄清,您希望您的编辑表单包含新的嵌套注册注释(并忽略任何其他现有注册注释)?我没有测试过这个,但你应该可以通过替换:

来做到这一点
  <%= r.fields_for :registration_notes do |n| %>

使用:

  <%= r.fields_for @registration.registration_notes.build do |n| %>

编辑:好的,通过对我自己的快速测试无效,但您可以这样做:

<%= r.fields_for :registration_notes do |n| %>
  <%= n.text_area :content if n.object.id.nil? %>
<% end %>

如果注册记事的ID为nil(即尚未保存),则只会添加文本区域。

另外,我实际上是先测试过它然后确实有效;)

答案 1 :(得分:3)

如果要在编辑操作上创建新的注册表单,可以只实例化一个新的registration_note对象。现在,您的表单是针对现有的注册对象。

我相信这就是你想要的:

class RegistrationsController < ApplicationController
  def edit
    @new_registration_note = RegistrationNote.new
    @registration = Registration.find(params[:id])
    @registration.registration_notes.build
  end
end

在您的视图中,您应该传递一个引用注册记录ID的隐藏参数:

<%= form_for @new_registration_note do |r| %>
  <%= r.hidden_field :registration_id, :value => @registration.id  %>
  <%= r.text_area :content  %>
<% end %>

现在,您可以创建属于 @registration的新注册记事。确保registration_notes表中有一列指向注册。您可以在此处详细了解关联:http://guides.rubyonrails.org/association_basics.html

答案 2 :(得分:3)

正如Heriberto Perez正确地指出,如果其中一个字段存在验证错误,那么最受欢迎的答案中的解决方案将简单地丢弃所有内容。

我的方法类似于Heriberto,但有点不同:

型号:

class Registration < ActiveRecord::Base
  has_many :registration_notes
  accepts_nested_attributes_for :registration_notes

  # Because 0 is never 1 this association will never return any records.
  # Above all this association don't return any existing persisted records.
  has_many :new_registration_notes, -> { where('0 = 1') }
                                  , class_name: 'RegistrationNote'
  accepts_nested_attributes_for :new_registration_notes
end

控制器:

class RegistrationsController < ApplicationController
  before_action :set_registration

  def edit        
    @registration.new_registration_notes.build
  end

  private

  def set_registration
    @registration = Registration.find(params[:id])
  end

  def new_registration_params
    params.require(:registration).permit(new_registrations_attributes: [:content])
  end
end

查看:

<%= form_for @registration do |r| %>
  <%= r.text_field :foo %>
  <%= r.text_field :bar %>
  <%= r.fields_for :new_registration_notes do |n| %>
    <%= n.text_area :content %>
  <% end %>
<% end %>

答案 3 :(得分:2)

非常感谢你的帮助,正如我在帖子中所说的那样,来自&#34; Zaid Crouch&#34;(我不知道如何引用用户hehe)的方法的唯一问题如果表单有错误字段,表单将清除并在页面重新加载后繁荣,您的表单中没有任何内容,并且您能想象如果您的表单是20或30个字段,这将是一个糟糕的用户体验当然

这是我使用验证模型的解决方案:

class Registration < ActiveRecord::Base
  attr_accessible :foo, :bar, :registration_notes_attributes
  has_many :registration_notes
  has_one :new_registration, class_name: 'RegistrationNote'
  accepts_nested_attributes_for :new_registration
end

class RegistrationsController < ApplicationController
  def edit
   @registration = Registration.find(params[:id])
   @registration.build_new_registration
  end
end

<%= form_for @registration do |r| %>
  <%= r.text_field :foo %>
  <%= r.text_field :bar %>
  <%= r.fields_for :new_registration do |n| %>
    <%= n.text_area :content %>
  <% end %>
<% end %>

我在我的示例中使用simple_form如果你想看到同样的验证和交易工作,请看看这里的完整帖子: http://elh.mx/ruby/using-simple_form-for-nested-attributes-models-in-a-has_many-relation-for-only-new-records/