Rails 4: accepts_nested_attributes_for и массовое назначение

Я пытаюсь воспроизвести railscast #196 в Rails 4. Однако я испытываю некоторые проблемы.

В моем примере я пытаюсь создать телефонную книгу - у каждого человека может быть несколько телефонных номеров.

Это важные части моего контроллера:

class PeopleController < ApplicationController
    def new
        @person = Person.new
        3.times{ @person.phones.build }
    end

    def create
        @person = Person.create(person_params)
        @person.phones.build(params[:person][:phones])

        redirect_to people_path
    end

private

    def person_params
        params.require(:person).permit(:id, :name, phones_attributes: [ :id, :number ])
    end
end

а это мой новый взгляд

<h1>New Person</h1>

<%= form_for :person, url: people_path do |f| %>
    <p>
        <%= f.label :name %> </ br>
        <%= f.text_field :name %>
    </p>

    <%= f.fields_for :phones do |f_num| %>
        <p>
            <%= f_num.label :number %> </ br>
            <%= f_num.text_field :number %>
        </p>
    <% end %>

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

Излишне говорить, что у меня есть has_many :phones и accepts_nested_attributes_for :phones в моей модели человека и belongs_to :person в модели телефона.

У меня есть следующие проблемы:

  1. Вместо 3-х полей для телефонных номеров в новой форме всего одно
  2. При отправке формы получаю ошибку:

Активмодел:: ФорбидденАтрибутесеррор

в соответствии

@person.phones.build(params[:person][:phones])

Параметры:

{"utf8"=>"✓",
 "authenticity_token"=>"l229r46mS3PCi2J1VqZ73ocMP+Ogi/yuYGUCMu7gmMw=",
 "person"=>{"name"=>"the_name",
 "phones"=>{"number"=>"12345"}},
 "commit"=>"Save Person"}

В принципе, я хотел бы сделать все это как объект формы, но я думаю, что если я даже не получу его с accepts_nested_attributes, у меня нет шансов сделать это как объект формы :(


person speendo    schedule 30.08.2013    source источник


Ответы (1)


Чтобы получить три телефона в представлении, измените form_for :person на form_for @person (вы хотите использовать объект, который вы создали здесь) следующим образом:

<%= form_for @person, url: people_path do |f| %>

Это также должно исправить ошибку ForbiddenAttributes.

И вашим create действием может быть:

def create
    @person = Person.create(person_params)

    redirect_to people_path
end

Обновление:

<%= form_for :person do |f| %> создает общую форму для модели Person и не знает о дополнительных деталях, которые вы применяете к конкретному объекту (в данном случае @person в вашем new действии). Вы прикрепили три поля phones к объекту @person, а @person не совпадает с :person, поэтому вы не видите три поля телефона в своем представлении. Дополнительные сведения см. по адресу: http://apidock.com/rails/ActionView/Helpers/FormHelper/form_for. Детали.

person vee    schedule 30.08.2013
comment
ура! Это решило обе проблемы - не могу сказать, как я рад! В базовом руководстве по рельсам используется хэш: guides.rubyonrails.org/getting_started. html#the-first-form — можете уточнить разницу? - person speendo; 31.08.2013
comment
@speendo, посмотрите обновление, если вы имели в виду разницу между использованием символа и использованием объекта. - person vee; 31.08.2013
comment
У меня есть комментарий вдогонку. Если модель телефона имеет phone_type_id и code def new @person = Person.new ph = Person.phone.build ph[:phone_type_id] = 1 ph2 = Person.phone.build ph2[:phone_type_id] = 2 end code Как бы представление знает идентификатор типа телефона и отправляет его обратно, не сохраняя code@personcode в конце нового метода? - person tandoan; 02.12.2013
comment
Это работает очень хорошо, но чего-то не хватает. Когда по какой-то причине входные данные недействительны и person не может быть создано, следуя тем же инструкциям, которые сказал @speendo, мы делаем render 'new', а поля phones (или в моем случае emails) исчезают. - person unmultimedio; 09.08.2015
comment
@unmultimedio, вам также нужно убедиться, что вы создали все необходимые ассоциации перед вызовом render 'new'. - person vee; 09.08.2015