从父表单创建一定数量的子对象

发布于 2024-08-18 15:40:02 字数 591 浏览 8 评论 0原文

感谢 Ruby on Rails:如何从表单中收集子表的值? 和“Agile Web Dev”,我知道如何使用 fields_for 在一个表单中拥有多个模型。但我正在为这件事抓狂。

假设我有一个模型 PersonPerson 有一个 name 属性和 has_many :foos。反过来,Foo 模型有一个 colour 属性。

此外,我知道每个Person恰好三个Foos。我的模型、PersonController 中的 new 和 create 操作以及 new 视图应该是什么样子,以便呈现三个标签精美的文本输入框,每个 Foo 一个,并且能够报告验证错误,以允许我的“新人”表单一次性创建整套四个对象?

另外,我可以在没有 accepts_nested_attributes_for 的情况下执行此操作吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

人海汹涌 2024-08-25 15:40:02

在尝试了不同位置的方括号和不同的 for 循环之后,我想我已经解决了这个问题。这是我的代码现在的样子(根据脚手架设置路由,以便从 /new 发布会触发 create)。

models/person.rb

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

models/foo.rbcontrollers

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

/people_controller.rbviews

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

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

这似乎可以解决问题。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文