Rails 3:nested_form、collection_select、accepts_nested_attributes_for 和 fields_for
这里和互联网上有很多关于如何让nested_form、collection_select、accepts_nested_attributes_for 和 fields_for 很好地协同工作的好问题和答案,但我仍然感到困惑。如果您能帮助我,请先致谢。
目标:生成新的 isbn 记录。一个 ISBN 可以有许多贡献者。我成功使用 ryanb Nested_form gem 在表单上动态生成新的贡献者字段,根据需要。这些字段之一使用 Contributor 中所有姓名记录的 collection_select 下拉列表。创建新记录时,需要将许多贡献者 ID 写入连接表 (contributors_isbns)。
我已经完成了部分工作,但仅限于我可以将单个贡献者 ID 保存到 isbns 表中的新记录中。我似乎无法将任何数据写入连接表。
我有三个模型。贡献者和 Isbn 具有多对多关系,我使用 has_many :through 完成了这一点。一个 isbn 可以有多个贡献者,一个贡献者可以有多个 isbn。他们通过contributors_isbn 加入。
isbn.rbcontributor.rbcontributors_isbn.rb
attr_accessible :contributor_id
has_many :contributors, :through => :contributors_isbns
has_many :contributors_isbns
accepts_nested_attributes_for :contributors
accepts_nested_attributes_for :contributors_isbns
在_fields
attr_accessible :isbn_id
has_many :contributors_isbns
has_many :isbns, :through => :contributors_isbns
accepts_nested_attributes_for :isbns
部分中,带有以下
class ContributorsIsbn
attr_accessible :isbn_id, :contributor_id
belongs_to :isbn
belongs_to :contributor
accepts_nested_attributes_for :contributors
在isbns控制器中:(
def new
@isbn = Isbn.new
@title = "Create new ISBN"
1.times {@isbn.contributors.build}
@isbn.contributors_isbns.build.build_contributor
end
显然我无法决定使用哪种构建方法。)
在isbnsnew.html.erb视图中:
<%= nested_form_for @isbn, :validate => false do |f| %>
<h1>Create new ISBN</h1>
<%= render 'shared/error_messages', :object => f.object %>
<%= render 'fields', :f => f %>
<div class="actions">
<%= f.submit "Create" %>
</div>
<% end %>
内容的版本:一个非常简单的文本字段:
<%= field_set_tag 'Contributor' do %>
<%= f.link_to_add "Add Additional Contributor", :contributors %>
<li>
<%= f.label 'Contributor Sequence Number' %>
<%= f.text_field :descriptivedetail_contributor_sequencenumber%>
</li>
<%= f.fields_for :contributors_isbns, :validate => false do |contrib| %>
<li>
<%= contrib.label :id, 'contributors_isbns id' %>
<%= contrib.text_field :id %>
</li>
<% end %>
<li>
<%= f.label 'Contributor Role' %>
<%= f.text_field :descriptivedetail_contributor_contributorrole %>
</li>
<% end %>
这里有一个更高级的版本,但也不起作用:
<%= f.fields_for :contributors_isbns, :validate => false do |contributors| %>
<li>
<%= f.label :personnameinverted, 'Contributor Name' %>
<%= f.collection_select(:contributor_id, Contributor.all, :id, :personnameinverted ) %>
</li>
<% end %>
此代码使用 此处。两者都会导致 nested_form_for @isbn
行出现“缺少块”错误。
再次非常感谢。
更新:这里是一些关于nested_form gem的信息,它可能会在解决这类问题时派上用场。这是一个[2009年但是仍然相关的帖子][4]关于accepts_nested_attributes_for。
更新2:好吧,我一直在两个不同的模型中研究这个的简化版本,没有使用collection_select或has_many,而只是简单地使用。父模型是 Contract,子模型是 Istc,但是,在查看堆栈并搜索后,我什至无法创建记录。错误消息“警告。无法批量分配受保护的属性” 我刚刚将 :istcs_attributes
添加到我的 :attr_accessible
行,现在我可以添加记录。缺少一个相当关键的位,并且RTFM 的情况,因为它就在 gem 自述文件中,我稍后会更新以查看这是否适用于更复杂的 has_many
更新 4:[这里][5] 是关于如何处理 a 的另一篇有用的文章 。更新 5:轻微
绕行 - 当我向表单动态添加一组新字段时,正在创建一个子记录 - 我在子表单区域内有“添加”链接。之前:
<%= f.fields_for :istcs do |istc_form| %>
<h4> Istc</h4>
<%= istc_form.label "istc name" %>
<%= istc_form.text_field :title_title_text %>
<%= istc_form.link_to_remove "[-] Remove this istc"%>
<%= f.link_to_add "[+] Add an istc", :istcs %>
<% end %>
这是之后:
<%= f.fields_for :istcs do |istc_form| %>
<h4> Istc</h4>
<%= istc_form.label "istc name" %>
<%= istc_form.text_field :title_title_text %>
<%= istc_form.link_to_remove "[-] Remove this istc"%>
<% end %>
<%= f.link_to_add "[+] Add an istc", :istcs %>
更新 6,后回答:
哦,不,collection_select 不起作用,它正在添加新的贡献者记录,而不是使用贡献者模型中的现有记录。 href="http://www.ruby-forum.com/topic/1446547" rel="nofollow noreferrer">其他人也遇到了这个问题。
There are lots of good questions and answers here and on the interweb about getting nested_form, collection_select, accepts_nested_attributes_for and fields_for to play nicely together, but I'm still stumped. Thanks in advance if you can help me.
Aim: To generate a new isbn record. An isbn can have many contributors. I am successfully using the ryanb nested_form gem to dynamically produce new contributor fields on a form, as required. One of these fields uses a collection_select drop down of all the name records in Contributor. When the new record is created, the many contributor ids need to be written to the join table (contributors_isbns).
I have got bits of this working, but only to the point where I can save a single contributor ID to the new record in the isbns table. I can't seem to get anywhere in writing any data to the join table.
I have three models. Contributors and Isbns have a many to many relationship, which I've done using has_many :through. An isbn can have many contributors, and a contributor can have many isbns. They are joined via contributors_isbn.
isbn.rb
attr_accessible :contributor_id
has_many :contributors, :through => :contributors_isbns
has_many :contributors_isbns
accepts_nested_attributes_for :contributors
accepts_nested_attributes_for :contributors_isbns
contributor.rb
attr_accessible :isbn_id
has_many :contributors_isbns
has_many :isbns, :through => :contributors_isbns
accepts_nested_attributes_for :isbns
contributors_isbn.rb
class ContributorsIsbn
attr_accessible :isbn_id, :contributor_id
belongs_to :isbn
belongs_to :contributor
accepts_nested_attributes_for :contributors
In the isbns controller:
def new
@isbn = Isbn.new
@title = "Create new ISBN"
1.times {@isbn.contributors.build}
@isbn.contributors_isbns.build.build_contributor
end
(obviously I can't make my mind up on which build method to use.)
In the isbns new.html.erb view:
<%= nested_form_for @isbn, :validate => false do |f| %>
<h1>Create new ISBN</h1>
<%= render 'shared/error_messages', :object => f.object %>
<%= render 'fields', :f => f %>
<div class="actions">
<%= f.submit "Create" %>
</div>
<% end %>
In the _fields partial, a version with a very plain text_field:
<%= field_set_tag 'Contributor' do %>
<%= f.link_to_add "Add Additional Contributor", :contributors %>
<li>
<%= f.label 'Contributor Sequence Number' %>
<%= f.text_field :descriptivedetail_contributor_sequencenumber%>
</li>
<%= f.fields_for :contributors_isbns, :validate => false do |contrib| %>
<li>
<%= contrib.label :id, 'contributors_isbns id' %>
<%= contrib.text_field :id %>
</li>
<% end %>
<li>
<%= f.label 'Contributor Role' %>
<%= f.text_field :descriptivedetail_contributor_contributorrole %>
</li>
<% end %>
And here, a fancier version which doesn't work either:
<%= f.fields_for :contributors_isbns, :validate => false do |contributors| %>
<li>
<%= f.label :personnameinverted, 'Contributor Name' %>
<%= f.collection_select(:contributor_id, Contributor.all, :id, :personnameinverted ) %>
</li>
<% end %>
This code uses the answer from here. Both result in a 'Missing block" error on the nested_form_for @isbn
line.
Thanks so much again in advance.
Update: here is some info about the nested_form gem which might come in handy for looking at this sort of problem. And here's a [2009 but still relevant post][4] on accepts_nested_attributes_for.
Update 2: well, here's a thing. I've been poking around on a cut-down version of this in two different models, not using collection_select or has_many through, but just on a simple belongs_to / has_many association. The parent model is Contract and the child model is Istc. I couldn't even create a record through the nested form. However, after looking in the stack and googling the error message "Warning. Can't mass-assign protected attributes" I've just added :istcs_attributes
to my :attr_accessible
line and now I can add records. A rather crucial bit missing, and a case of RTFM, as it's right there in the gem readme. I'll update later to see if this works on the more complicated has_many through association.
Update 4: [Here][5] is another useful post about how to deal with a nil record error message.
Update 5: Slight detour - When I dynamically added a new set of fields to the form, one one of the child records was being created. Duh - I had the "Add" link inside the child forms area. Here's the before:
<%= f.fields_for :istcs do |istc_form| %>
<h4> Istc</h4>
<%= istc_form.label "istc name" %>
<%= istc_form.text_field :title_title_text %>
<%= istc_form.link_to_remove "[-] Remove this istc"%>
<%= f.link_to_add "[+] Add an istc", :istcs %>
<% end %>
and here's the after:
<%= f.fields_for :istcs do |istc_form| %>
<h4> Istc</h4>
<%= istc_form.label "istc name" %>
<%= istc_form.text_field :title_title_text %>
<%= istc_form.link_to_remove "[-] Remove this istc"%>
<% end %>
<%= f.link_to_add "[+] Add an istc", :istcs %>
Update 6, post-answer:
Oh noes. The collection_select isn't working. It's adding new contributor records, not using an existing one from the contributor model. Someone else had this problem too. Any ideas?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
好哇!这是使这一切工作的代码。有点冗长,但不想遗漏任何内容。我的主要学习内容:
您需要在父模型中使子属性 attr_accessible
您需要在联接表模型
如果您在父控制器中构建至少一个子实例,那么生活会更轻松。
模型
isbn.rb模型
contributors_isbn模型
isbn控制器
new.html.erb_fields.html.erb
贡献者.rb
Huzzah! Here's the code which makes all this work. Bit verbose but didn't want to leave anything out. My main learnings:
you need to make the child attributes attr_accessible in the parent model
you need to make the parent and child ids attr_accessible in the join table model
it makes life easier if you build at least one child instance in the parent controller.
contributor.rb model
isbn.rb model
contributors_isbn model
isbn controller
new.html.erb
_fields.html.erb