从父窗体创建一定数量的子对象 [英] Creating a set number of child objects from a parent's form

查看:169
本文介绍了从父窗体创建一定数量的子对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

感谢 Ruby on Rails:如何从表单收集子表的值?和Agile Web Dev,I知道如何使用 fields_for 在表单中创建多个模型。但是我正在撕掉我的头发。



假设我有一个模型 Person Person 具有名称属性,并且 has_many:foos Foo 模型反过来具有颜色属性。



此外,我知道每个 Person 都有正好三个 Foos 。我的模型, new PersonController >和视图看起来像是为了呈现三个标记为好的文本输入框,每个Foo一个,并且能够报告验证错误,以允许我的新人的形式来创建一整套四个对象?

另外,我可以做到这一点没有 acceptersted_attributes_for

解决方案

在玩过方形大括号和不同循环的不同位置后,我想我解决了这个问题。这是我的代码现在的样子(根据脚手架设置路线,以便从 / new >触发 create )。

models / person.rb

  class Person< ActiveRecord :: Base 
has_many:foos
validates_presence_of:name
end

models / foo.rb

  class Foo< ActiveRecord :: Base 
belongs_to:person
validates_presence_of:color
validates_uniqueness_of:color,:scope => person_id
end

controllers / people_controller.rb

  def new 
#设置一个有3个默认Foos的人
@person = Person.new
(1..3 ).each {| i | @ person.foos.build}
结束

def创建
#创建(但不保存)指定的人
@person = Person.new( params [:person])

#为每组Foo细节创建(但不保存)Foo
@foos = []
params [:foo]。每个都做| foo_param |
@foos<< Foo.new(foo_param)
结束

#在交易中保存所有内容
Person.transaction do
@ person.save!
@ foos.each do | foo |
foo.person = @person
foo.save!
结束
结束

redirect_to:action => 'show',:id => @person

rescue ActiveRecord :: RecordInvalid => e
@ foos.each do | foo |
foo.valid?
结束
render:action => 'new'
end

views / people / new.html.erb

 <%form_for:person do | f | %GT; 
<%= error_messages_for:object => [@person] + @ person.foos%>

< p>
<%= f.label:name%>< br />
<%= f.text_field:name%>
< / p>

< table>
<%@ person.foos.each_with_index do | foo,index | @foo = foo%>
< tr>
< td><%= label:color,Foo color#{index + 1}:%>< / td>
< td><%= text_field(foo [],color%>< / td>
< / tr>
<%end%> ;
< / table>

< p>
<%= f.submit'创建'%>
< / p>
<%end%>>

这似乎是个窍门。


Thanks to Ruby on Rails: How to gather values for child tables from a form? and "Agile Web Dev", I know how to have multiple models in a form using fields_for. But I'm tearing my hair out over this one.

Suppose I have a model Person. Person has a name attribute, and has_many :foos. The Foo model, in turn, has a colour attribute.

Furthermore, I know that each Person has precisely three Foos. What should my Models, the new and create actions in PersonController, and the new view look like in order to present three nicely-labelled text-entry boxes, one for each Foo and capable of reporting validation errors, to allow my "new person" form to create the whole set of four objects in one go?

Also, can I do this without accepts_nested_attributes_for?

解决方案

After some playing about with varied locations for square braces and different for loops, I think I've solved this. Here's what my code looks like now (with routes set up as per scaffolding, so that posting from /new triggers create).

models/person.rb

class Person < ActiveRecord::Base
  has_many :foos
  validates_presence_of :name
end

models/foo.rb

class Foo < ActiveRecord::Base
  belongs_to :person
  validates_presence_of :colour
  validates_uniqueness_of :colour, :scope => "person_id"
end

controllers/people_controller.rb

def new
  # Set up a Person with 3 defaulted Foos
  @person = Person.new
  (1..3).each { |i| @person.foos.build }
end

def create
  # Create (but don't save) a Person as specified
  @person = Person.new(params[:person])

  # Create (but don't save) a Foo for each set of Foo details
  @foos = []
  params[:foo].each do |foo_param|
    @foos << Foo.new(foo_param)
  end

  # Save everything in a transaction
  Person.transaction do
    @person.save!
    @foos.each do |foo|
      foo.person = @person
      foo.save!
    end
  end

  redirect_to :action => 'show', :id => @person

rescue ActiveRecord::RecordInvalid => e
  @foos.each do |foo|
    foo.valid?
  end
  render :action => 'new'
end

views/people/new.html.erb

<% form_for :person do |f| %>
  <%= error_messages_for :object => [@person] + @person.foos %>

  <p>
    <%= f.label :name %><br />
    <%= f.text_field :name %>
  </p>

  <table>
  <% @person.foos.each_with_index do |foo, index| @foo = foo%>
    <tr>
      <td><%= label :colour, "Foo colour #{index + 1}: " %></td>
      <td><%= text_field("foo[]", "colour" %></td>
    </tr>          
  <% end %>
  </table>

  <p>
    <%= f.submit 'Create' %>
  </p>
<% end %>

This seems to do the trick.

这篇关于从父窗体创建一定数量的子对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆