Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deeply nested Rails forms using belong_to not working?

I'm working on a messy form which among other things has to manage a section with two-level nesting. It's almost working, but there's a snag and the only thing I can see that's different from other deeply-nested forms that work is that there's a belongs_to relationship rather than has_many. Here are the models:

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

So it's a fairly standard many-to-many relationship via a link table, company_events. The form in question is creating/editing an event, with a dynamic "Add Company" Javascript button, all pretty much based on Ryan Bates' screencast and GitHub repo.

The main form:

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

And the included form is as follows. An important thing to note is that the company ID is set via a Javascript update, which I won't include here because it's long. Basically the user starts typing a name, an autocomplete list is displayed, and clicking on the name sets both the company name and the id in the form.

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

When I update an existing record, everything works just fine. When I try to save the form with a newly-created record, though, I get:

ActiveRecord::RecordNotFound in EventsController#update

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

With the stacktrace:

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

I've looked through the code in nested_attributes, and run through it with a debugger. What's happening seems to be that because there's a Company.id, ActiveRecord is assuming that there is already an entry, but then of course it doesn't find one. This seems very odd, since obviously I'd need to pass in an ID in order to create a new CompanyEvent entry. So, I'm guessing that I'm missing something.

The examples I've found that work all seem to be nested using has_many relationships all the way down, while in this case it's a belongs_to, and I'm wondering if that's the root of the problem. Any ideas would be greatly appreciated...

like image 791
Masonoise Avatar asked Sep 23 '10 23:09

Masonoise


1 Answers

Here's another possible solution that I posted in a similar question: https://stackoverflow.com/a/12064875/47185

Something like this...

  accepts_nested_attributes_for :company
  def company_attributes=(attributes)
    if attributes['id'].present?
      self.company = Company.find(attributes['id'])
    end
    super
  end
like image 159
Tyler Rick Avatar answered Sep 26 '22 19:09

Tyler Rick