Глубоко вложенные формы Rails, использующие принадлежащие_, не работают? - PullRequest
6 голосов
/ 24 сентября 2010

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

Event
  has_many :company_events, :dependent => :destroy
  accepts_nested_attributes_for :company_events

CompanyEvent
  belongs_to :company
  accepts_nested_attributes_for :company, :update_only => true
  belongs_to :event
  belongs_to :event_type

Company
  has_many :company_events
  has_many :events, :through => :company_events

Так что это довольно стандартное отношение «многие ко многим» через таблицу ссылок, company_events.Форма, о которой идет речь, - это создание / редактирование события с динамической кнопкой Javascript «Добавить компанию», все в значительной степени основанной на скринкасте Райана Бейтса и репозитории GitHub.

Основная форма:

<table id="companies">
  <tr><th>Company Name</th></tr>
  <% f.fields_for :company_events do |builder| %>
    <%= render 'company_event_fields', :f => builder, :f_o => nil %>
  <% end -%>
</table>
<p><br/><%= link_to_add_fields "Add Company", f, :company_events, "events" %></p>

А включенная форма выглядит следующим образом.Важно отметить, что идентификатор компании устанавливается через обновление Javascript, которое я не буду здесь включать, потому что оно длинное.Обычно пользователь начинает вводить имя, отображается список автозаполнения, и при щелчке по имени в форме указываются как название компании, так и идентификатор.

<tr class="company_event_fields">
  <td>
    <% f.fields_for(:company) do |company_form| -%>
      <%= company_form.text_field :name, :size => 80 %>
      <%= company_form.hidden_field :id %>
    <% end -%>
  </td>
  <td>
    <%= f.hidden_field :_destroy %>
    <%= link_to_function "remove", "remove_co_fields(this)" %>
  </td>
</tr>

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

ActiveRecord::RecordNotFound in EventsController#update

Couldn't find Company with ID=12345 for CompanyEvent with ID=

С помощью трассировки стека:

/Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/nested_attributes.rb:401:in `raise_nested_attributes_record_not_found'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/nested_attributes.rb:289:in `assign_nested_attributes_for_one_to_one_association'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/nested_attributes.rb:244:in `company_attributes='
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/base.rb:2906:in `send'

Я просмотрел код в nested_attributesи запустить его с помощью отладчика.Кажется, что происходит из-за того, что существует Company.id, ActiveRecord предполагает, что запись уже есть, но, конечно, она не находит.Это кажется очень странным, поскольку, очевидно, мне нужно будет ввести идентификатор для создания новой записи CompanyEvent.Итак, я предполагаю, что мне чего-то не хватает.

Примеры, которые я обнаружил, что все работы кажутся вложенными, используя отношения has_many, вплоть до самого конца, тогда как в этом случае это - own_to, и ямне интересно, в этом ли корень проблемы.Любые идеи будут с благодарностью ...

Ответы [ 2 ]

13 голосов
/ 23 августа 2012

Вот еще одно возможное решение, которое я разместил в похожем вопросе: https://stackoverflow.com/a/12064875/47185

Как то так ...

  accepts_nested_attributes_for :company
  def company_attributes=(attributes)
    if attributes['id'].present?
      self.company = Company.find(attributes['id'])
    end
    super
  end
4 голосов
/ 10 декабря 2010

Я столкнулся с той же проблемой, просто кажется, что рельсы не поддерживают использование вложенных моделей, таких как это: вы не можете сохранить новый объект с существующей вложенной моделью, например, представьте себе такую ​​ситуацию:

class Monkey < ActiveRecord::Base
end
class Banana < ActiveRecord::Base
    belongs_to :monkey
    accepts_nested_attributes_for :monkey
end

Это не будет работать, если вы попробуете на консоли:

banana = Banana.create!
monkey = Monkey.new
monkey.attributes = {:banana_attributes => { :id => banana.id}}

Но это просто обойти, в вашей форме вам не нужно устанавливать какие-либо вложенные атрибуты, если ваш банан уже постоянен, вам просто нужно иметь скрытое поле в форме обезьяны с banana_id, что приведет к чему-то вроде:

monkey.attributes = {:banana_id => banana.id}

И это сэкономит очень хорошо.

...