Ruby-on-rails 如何让 Rails build 和 fields_for 只创建一个新记录而不包括现有记录?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14884704/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 21:24:46  来源:igfitidea点击:

How to get Rails build and fields_for to create only a new record and not include existing?

ruby-on-rails

提问by Jason Galuten

I am using build, fields_for, and accepts_nested_attributes_forto create a new registration note on the same form as a new registration (has many registration notes). Great.

我正在使用build,fields_foraccepts_nested_attributes_for在与新注册相同的表单上创建新注册备注(有许多注册备注)。伟大的。

Problem: On the edit form for the existing registration, I want another new registration note to be created, but I don't want to see a field for each of the existing registration notes.

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

I have this

我有这个

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

and this

和这个

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

and in the view I am doing this:

在我看来,我正在这样做:

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

and it is creating a blank text area for a new registration note (good) andeach existing registration note for that registration (no thank you).

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

Is there a way to only create a new note for that registration and leave the existing ones alone?

有没有办法只为该注册创建一个新的笔记,而不管现有的笔记?

回答by Zaid Crouch

EDIT: My previous answer (see below) was bugging me because it's not very nice (it still loops through all the other registration_notesneedlessly). After reading the API a bit more, the best way to get the behaviour the OP wanted is to replace:

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

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

with:

和:

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

fields_foroptionally takes a second parameter which is the specific object to pass to the builder (see the API), which is built inline. It's probably actually better to create and pass the new note in the controller instead of in the form though (just to move the logic out of the view).

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



Original answer (I was so close):

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

Just to clarify, you want your edit form to include a new nested registration note (and ignore any other existing ones)? I haven't tested this, but you should be able to do so by replacing:

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

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

with:

和:

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

EDIT: Okay, from a quick test of my own that doesn't work, but instead you can do:

编辑:好的,从我自己的快速测试来看,它不起作用,但你可以这样做:

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

This will only add the text area if the id of the registration note is nil (ie. it hasn't been saved yet).

如果注册说明的 id 为零(即尚未保存),则只会添加文本区域。

Also, I actually tested this first and it does work ;)

另外,我实际上首先对此进行了测试,并且确实有效;)

回答by Huy

If you want to create a new registration form on your edit action, you can just instantiate a new registration_note object. Right now, your form is for the existing registration object.

如果你想在你的编辑操作上创建一个新的注册表单,你可以实例化一个新的 registration_note 对象。现在,您的表单用于现有的注册对象。

I believe this is what you want:

我相信这就是你想要的:

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

In your view, you should pass a hidden param that references the registration record id:

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

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

Now, you can create your new registration note that belongs to@registration. Make sure you have a column in your registration_notestable to point to the registration. You can read more about associations here: http://guides.rubyonrails.org/association_basics.html

现在,您可以创建属于@registration. 确保您的registration_notes表格中有一个列指向注册。您可以在此处阅读有关关联的更多信息:http: //guides.rubyonrails.org/association_basics.html

回答by heriberto perez

Thank you so much for your help as I said in my post the only problem with the approach from "Zaid Crouch"(I don't know how to make a reference to a user hehe) is that if the form has error fields the form will be clear and boom after the page reloading you'll have nothing filled in your form and can you imagine if you form is like 20 or 30 fields that would be a terrible user experience of course

非常感谢您的帮助,正如我在我的帖子中所说,“Zaid Crouch”(我不知道如何引用用户呵呵)的方法的唯一问题是,如果表单有错误字段,则表单页面重新加载后会变得清晰和繁荣,你的表单中什么也没有填写,你能想象如果你的表单有 20 或 30 个字段,这当然会是一个糟糕的用户体验

Here is my solution that works with validation models:

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

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

I'm using simple_form in my example if you want to see the same working with validations and transaction take a look at the complete post here: http://elh.mx/ruby/using-simple_form-for-nested-attributes-models-in-a-has_many-relation-for-only-new-records/

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

回答by Fabian Winkler

As Heriberto Perez correctly pointed out the solution in the most upvoted answer will simply discard everything if there's a validation error on one of the fields.

正如 Heriberto Perez 正确地指出,如果其中一个字段出现验证错误,则最高投票答案中的解决方案将简单地丢弃所有内容。

My approach is similar to Heriberto's but nevertheless a bit different:

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

Model:

模型:

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

Controller:

控制器:

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

View:

看法:

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