Nested Routes allow for actions only if IDs match??

Hello,

I'm encountering a very strange issue and I've identified behavior I
don't quite understand. I have a design in which a "full model" exists
with sub-screens for each of the pages worth of data input. Each screen
goes through validation, and then updates the overall model with the
validated input, as well as saving the screen's information to a
specific "screen" table.

For instance:

class FullQuoteHoModel < ActiveRecord::Base
  has_one :full_quote_ho
  has_one :full_quote_ho_loc
  has_one :full_quote_ho_cov
  has_one :full_quote_ho_additional_coverage

end

class FullQuoteHo < ActiveRecord::Base
  belongs_to :full_quote_ho_model
end

class FullQuoteHoLoc < ActiveRecord::Base
  belongs_to :full_quote_ho_model
end

class FullQuoteHoCov < ActiveRecord::Base
  belongs_to :full_quote_ho_model
end

class FullQuoteHoAdditionalCoverage < ActiveRecord::Base
  belongs_to :full_quote_ho_model
end

FullQuoteHoModel is the "entire" model, with each of the others as
"sub-screens" that accept inputs, validate them, save the values to
their tables, and also update the accepted, validated inputs into the
"entire" model.

I only want index/show/new/destroy in the FullQuoteHoModel, and I only
want new/create/edit/update in the sub-screens. I do this in the routes
file as follows:

  map.resources :full_quote_ho_models, :except => [:edit, :update,
:create], :requirements => {:id => /[0-9]+/} do |full_quote_ho_model|
    full_quote_ho_model.resources :full_quote_ho_additional_coverages,
:only => [:new, :create, :edit, :update], :requirements => {:id =>
/[0-9]+/}, :name_prefix => nil
    full_quote_ho_model.resources :full_quote_ho_covs, :only => [:new,
:create, :edit, :update], :requirements => {:id => /[0-9]+/},
:name_prefix => nil
    full_quote_ho_model.resources :full_quote_ho_locs, :only => [:new,
:create, :edit, :update], :requirements => {:id => /[0-9]+/},
:name_prefix => nil
    full_quote_ho_model.resources :full_quote_hos, :only => [:new,
:create, :edit, :update], :requirements => {:id => /[0-9]+/},
:name_prefix => nil
  end

Now, when I create a new full quote ho model from the FullQuoteHoModel
index screen, I can create each of the screens just fine, as well as the
overall model (for testing purposes, there is no validation above, so I
create empty records that are assigned system-generated IDs).

When I access any screen from the FullQuoteHoModel, if it has the same
ID path as the FullQuoteHoModel, things show up and work as intended.
However, if the ID of the screen is not the same as the
FullQuoteHoModel, then I receive the following error:

ActionController::RoutingError in Full_quote_hos#edit

Showing app/views/full_quote_hos/edit.html.erb where line #3 raised:

full_quote_ho_url failed to generate from {:action=>"update",
:full_quote_ho_model_id=>#<FullQuoteHo id: 4, inception_date: "",
building_construction: nil, protection_class: nil, territory: "",
policy_form: "", replacement_cost_on_contents: "", occupancy_type: "",
building_type: "", applicants_first_name: "", applicants_middle_initial:
"", applicants_last_name: "", applicants_date_of_birth: "",
applicants_ssn: "", coapplicants_first_name: "",
coapplicants_middle_initial: "", coapplicants_last_name: "",
coapplicants_date_of_birth: "", coapplicants_ssn: "",
property_address_1: "", property_address_2: "", property_zip_code: "",
property_county: "", property_city: "", property_state: "",
property_city_limits: "", property_address_how_long: "",
mailing_address_1: "", mailing_address_2: "", mailing_zip_code: "",
mailing_county: "", mailing_city: "", mailing_state: "",
previous_address_1: "", previous_address_2: "", previous_zip_code: "",
previous_county: "", previous_city: "", previous_state: "",
currently_insured: "", current_carrier: "", created_at: "2009-06-23
05:45:03", updated_at: "2009-06-23 05:45:03", full_quote_ho_model_id:
3>, :controller=>"full_quote_hos"}, expected: {:action=>"update",
:controller=>"full_quote_hos"}, diff:
{:full_quote_ho_model_id=>#<FullQuoteHo id: 4, inception_date: "",
building_construction: nil, protection_class: nil, territory: "",
policy_form: "", replacement_cost_on_contents: "", occupancy_type: "",
building_type: "", applicants_first_name: "", applicants_middle_initial:
"", applicants_last_name: "", applicants_date_of_birth: "",
applicants_ssn: "", coapplicants_first_name: "",
coapplicants_middle_initial: "", coapplicants_last_name: "",
coapplicants_date_of_birth: "", coapplicants_ssn: "",
property_address_1: "", property_address_2: "", property_zip_code: "",
property_county: "", property_city: "", property_state: "",
property_city_limits: "", property_address_how_long: "",
mailing_address_1: "", mailing_address_2: "", mailing_zip_code: "",
mailing_county: "", mailing_city: "", mailing_state: "",
previous_address_1: "", previous_address_2: "", previous_zip_code: "",
previous_county: "", previous_city: "", previous_state: "",
currently_insured: "", current_carrier: "", created_at: "2009-06-23
05:45:03", updated_at: "2009-06-23 05:45:03", full_quote_ho_model_id:
3>}

Extracted source (around line #3):

1: <h1>Editing Full Quote Homeowners: Basic Information</h1>
2:
3: <% form_for(@full_quote_ho) do |f| %>
4: <%= error_messages_for :full_quote_ho, :header_message =>
"#{@full_quote_ho.errors.count} validation errors prohibited this Full
Quote Screen from being validated.", :message => "Please correct the
fields in red and try again." %>
5:

This is an issue because currently, a user can create a new
FullQuoteHoModel, fill out two screens, then hit Back and go to the
FullQuoteHoModel index, maybe create a new FullQuoteHoModel, fill out
all screens, then decide to return to the first one and create the
remaining two screens. The IDs are then out of sync (which isn't
unintended behavior - technically speaking, no matter what the ID of the
screen, it belongs to one and only one FullQuoteHoModel) and trying to
go back and edit that screen doesn't show up. Is this a routing issue
(the generated URLs, maybe)? Or something else?

The index page shows the ability to create or edit screens as follows
per FullQuoteHoModel record:

    <% @full_quote_ho_models.each do |full_quote_ho_model| %>
    <tr>
      <td><%=h full_quote_ho_model.inception_date %></td>
      <td><%=h full_quote_ho_model.policy_form %></td>
      <td><%=h full_quote_ho_model.applicants_first_name %></td>
      <td><%=h full_quote_ho_model.applicants_middle_initial %></td>
      <td><%=h full_quote_ho_model.applicants_last_name %></td>
      <td><%=h full_quote_ho_model.applicants_ssn %></td>
      <td><%=h full_quote_ho_model.property_address_1 %></td>
      <td><%=h full_quote_ho_model.property_address_2 %></td>
      <td><%=h full_quote_ho_model.property_zip_code %></td>
      <td><%=h full_quote_ho_model.property_county %></td>
      <td><%=h full_quote_ho_model.property_city %></td>
      <td><%=h full_quote_ho_model.property_state %></td>
    </tr>
    <tr>
      <td colspan="1"><%= link_to 'Show', full_quote_ho_model %></td>

      <% if full_quote_ho_model.full_quote_ho != nil %>
      <td colspan="2"><%= link_to 'Edit Basic Information',
edit_full_quote_ho_path(full_quote_ho_model.id,
full_quote_ho_model.full_quote_ho.id) %></td>
      <% else %>
      <td colspan="2"><%= link_to 'Continue Basic Information',
new_full_quote_ho_path(full_quote_ho_model.id) %></td>
      <% end %>

      <% if full_quote_ho_model.full_quote_ho_loc != nil %>
      <td colspan="2"><%= link_to 'Edit Locations',
edit_full_quote_ho_loc_path(full_quote_ho_model.id,
full_quote_ho_model.full_quote_ho_loc.id) %></td>
      <% else %>
      <td colspan="2"><%= link_to 'Continue Locations',
new_full_quote_ho_loc_path(full_quote_ho_model.id) %></td>
      <% end %>

      <% if full_quote_ho_model.full_quote_ho_cov != nil %>
      <td colspan="2"><%= link_to 'Edit Coverages',
edit_full_quote_ho_cov_path(full_quote_ho_model.id,
full_quote_ho_model.full_quote_ho_cov.id) %></td>
      <% else %>
      <td colspan="2"><%= link_to 'Continue Coverages',
new_full_quote_ho_cov_path(full_quote_ho_model.id) %></td>
      <% end %>

      <% if full_quote_ho_model.full_quote_ho_additional_coverage != nil
%>
      <td colspan="2"><%= link_to 'Edit Additional Coverages',
edit_full_quote_ho_additional_coverage_path(full_quote_ho_model.id,
full_quote_ho_model.full_quote_ho_additional_coverage.id) %></td>
      <% else %>
      <td colspan="2"><%= link_to 'Continue Additional Coverages',
new_full_quote_ho_additional_coverage_path(full_quote_ho_model.id)
%></td>
      <% end %>

      <td colspan="1"><%= link_to 'Destroy', full_quote_ho_model,
:confirm => 'Are you sure?', :method => :delete %></td>
    </tr>

If I try and alter the generated URLs to not include IDs, I receive
errors. I know the ordering of the IDs is appropriate. The pathing
should be as it currently is: /full_quote_ho_models/#/full_quote_ho/# or
/full_quote_ho_models/#/full_quote_ho_locs/#, etc.

Has anyone seen this behavior before?

Have you tried explicitly setting the URL to post to in the form_for?
From the trace, it looks like it's trying to generate a route to
edit_full_quote_ho without specifying the parent model.
[@full_quote_ho_model, @full_quote_ho] might work as well.

--Matt Jones

Matt Jones wrote:

Have you tried explicitly setting the URL to post to in the form_for?
From the trace, it looks like it's trying to generate a route to
edit_full_quote_ho without specifying the parent model.
[@full_quote_ho_model, @full_quote_ho] might work as well.

--Matt Jones

On Jun 23, 2:02�am, Ahad Amdani <rails-mailing-l...@andreas-s.net>

No, I haven't tried explicitly setting the URL. I'm trying to do this
the proper way within the Rails framework, and I wanted to utilize the
helpers/paths.

[@full_quote_ho_model, @full_quote_ho] didn't work and caused similar
issues.

As I said earlier, if the IDs for the parent model and it's nested
models are the same, everything works fine - but if not, that's when
there is an error. So, I have a feeling it isn't my view code/URLs, but
rather the logic behind how I have things routed and/or designed.