Ruby on Rails создает несколько дочерних элементов в одной родительской форме

У меня есть родитель, у которого несколько детей. Я хочу, чтобы при отправке формы в родительской модели создавался родительский элемент, а в дочерней модели создавалось несколько записей, по одной для каждого дочернего элемента. Когда я пытаюсь отправить, я получаю следующую ошибку:

 ActiveRecord::AssociationTypeMismatch in ParentsController#create

   Child(#) expected, got Array(#)

Когда я раскомментирую accept_nested_attributes_for: children и меняю f.fields_for: children на f.fields_for: children_attributes, я получаю другую ошибку:

  TypeError in ParentsController#create

    can't convert Symbol into Integer

Я не понимаю, что мне делать. Я проверил вложенные модели railscasts, но они имели дело с генерацией дочерних полей внутри формы, и то, что я узнал из railscasts, похоже, не сработало. Я хорош, я неправильно делаю свой builder.text_field: cname в моей форме, но я не знаю, как это сделать.

Мой код:

parent.rb

class Parent < ActiveRecord::Base
  has_many :children
  #accepts_nested_attributes_for :children
  attr_protected :id

child.rb

class Child < ActiveRecord::Base
  belongs_to :parent
  attr_protected :id

_form.html.erb

<%= form_for @parent, :url => { :action => "create" } do |f| %>
  <%= f.text_field :pname %>
  <%= f.fields_for :children do |builder| %>
    <%= builder.text_field :cname %>
    <%= builder.text_field :cname %>
    <%= builder.text_field :cname %>
  <% end %>
  <%= f.submit %>
<% end %>

содержание params:

{"utf8"=>"✓",
 "authenticity_token"=>"FQQ1KdNnxLXolfes9IGiO+aKHJaPCH+2ltDdA0TwF7w=",
 "parent"=>{"pname"=>"Heman",
 "child"=>{"cname"=>""}},
 "commit"=>"Create"}

person notblakeshelton    schedule 03.07.2013    source источник
comment
Можете ли вы опубликовать params, содержащий атрибуты для детей, при отправке формы, пожалуйста? Я почти уверен, что вам просто нужно зацикливаться на params[:children], поскольку ваш журнал ошибок сообщает нам, что это массив   -  person MrYoshiji    schedule 03.07.2013
comment
@MrYoshiji, возможно, ты снова придёшь мне на помощь. Я обновил свой вопрос параметрами. Появляется только один ребенок, и он не отображает никаких имен.   -  person notblakeshelton    schedule 03.07.2013
comment
Ах, я узнал это ... Подождите, я отправлю ответ, а вы можете взглянуть на очень похожую проблему: stackoverflow.com/questions/16919711/   -  person MrYoshiji    schedule 03.07.2013


Ответы (1)


Проблема здесь в том, что сгенерированная форма в HTML для детей использует одно и то же «место» (та же пара ключ / значение) в параметрах Hash (с использованием пары params[:parent][:child][:cname]). Вот почему в «дочернем» узле хэша Params есть только одно имя параметра.

Чтобы этого избежать, вы можете использовать массив для имени входа:

<input type="text" name="child[][cname]" />
<input type="text" name="child[][cname]" />

После отправки параметры будут выглядеть так:

params: {
  child: [ { cname: 'blabla' }, { cname: 'bonjour' } ]
}

Чтобы получить желаемый результат, в вашем случае:

<%= form_for @parent, :url => { :action => "create" } do |f| %>
  <%= f.text_field :pname %>

  <%= text_field_tag "parent[children][][cname]" %>
  <%= text_field_tag "parent[children][][cname]" %>
  <%= text_field_tag "parent[children][][cname]" %>

  <%= f.submit %>
<% end %>

Должно получиться что-то вроде этого:

{
  "utf8"=>"✓",
  "authenticity_token"=>"FQQ1KdNnxLXolfes9IGiO+aKHJaPCH+2ltDdA0TwF7w=",
  "parent"=> { 
    "pname"=>"Heman",
    "children"=> [
      { "cname"=>"SisiSenior" },
      { "cname"=>"Bonjor" },
      { "cname"=>"Blabla" }
    ]
  },
  "commit"=>"Create"}

Итак, в вашем контроллере вы можете использовать что-то вроде этого:

#ParentsController
def create
  children_attributes = params[:parent].delete(:children) # takes off the attributes of the children
  @parent = Parent.create(params[:parent])

  children_attributes.each do |child_attributes|
    child = @parent.children.create(child_attributes)
  end
end
person MrYoshiji    schedule 03.07.2013
comment
святые ведра товарищ. ты спасатель. Слава так много. И, конечно, пусть твой меч останется острым, а конь - быстрым. - person notblakeshelton; 03.07.2013
comment
извините за это, но я подумал, что это было слишком просто, чтобы быть новым вопросом. есть ли способ сделать так, чтобы запись создавалась только в том случае, если имя не пустое? Я подумал, что будет работать просто использовать конец if #something! = Nil [email protected] (child_attributes), но я не знаю, что поставить вместо #something. - person notblakeshelton; 04.07.2013
comment
неважно, я понял это. я заменил #something! = nil на child_attributes [name]! = - person notblakeshelton; 04.07.2013