Создание заданного количества дочерних объектов из родительской формы - PullRequest
3 голосов
/ 21 января 2010

Благодаря Ruby on Rails: как собрать значения для дочерних таблиц из формы? и "Agile Web Dev", я знаю, как создать несколько моделей в форме, используя fields_for. Но я рву волосы над этим.

Предположим, у меня есть модель Person. Person имеет атрибут name и has_many :foos. Модель Foo, в свою очередь, имеет атрибут colour.

Кроме того, я знаю, что у каждого Person есть точно три Foos. Как должны выглядеть мои Модели, действия new и create в PersonController и представление new, чтобы представить три красиво помеченных поля ввода текста, по одному для каждого Foo, и сообщать об ошибках проверки , чтобы моя форма "новый человек" позволила создать целый набор из четырех объектов за один раз?

Кроме того, я могу сделать это без accepts_nested_attributes_for?

1 Ответ

3 голосов
/ 22 января 2010

После некоторой игры с различными местами для квадратных скобок и разными для циклов, я думаю, что я решил это. Вот как теперь выглядит мой код (с маршрутами, настроенными в соответствии со скаффолдингом, поэтому отправка из /new вызывает create).

Модели / person.rb

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

Модели / foo.rb

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

Контроллеры / 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

Вид / чел / 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 %>

Кажется, это помогает.

...