2

I've been banging my head on this issue for about 2 hours now. This makes no sense to me. I'm trying to to write a simple form helper that is 3 level nested. (I'm aware that 3 level nests are not recommended, but just roll with me here for a second.)

My routes.rb excerpt looks like this:

resources :vendors, path: '', except: [:new, :create] do

  resources :item_links do
    resources :messages
  end

  resources :projects do
    resources :designs
  end

end

Now when I render the following, it errors out:

<%= form_for [@vendor, @item_link, Message.new], url: vendor_item_link_messages_path, method: :post, remote: true do |f| %>

No route matches {:action=>"index", :controller=>"messages", :vendor_id=>"thearborist", :project_id=>"4fad5bd7", :id=>"77ec58b5"} missing required keys: [:item_link_id]

I'm specifying the url here because my Vendor class and my ItemLink class both have sub-classes (sti) and if I don't specify the url, I end up with the fully qualified route which I don't want.

Based on the error, its ignoring the method param I specified entirely because its trying to access the "index" action instead of the "create" action. Secondly, its inserting a project_id param into the equation for some reason that makes no sense. Nowhere in either the params specified or the url path I listed does it reference project.

Furthermore, I decided to go specific and list out routes to my specfic sub-classes:

resources :vendor_arborists do
  resources :item_link_standards do
    resources :messages
  end
end

This still blows up with the same sort of error

<%= form_for [@vendor, @item_link, Message.new], url: vendor_arborist_item_link_standard_messages_path, method: :post, remote: true do |f| %>

No route matches {:action=>"index", :controller=>"messages", :vendor_id=>"thearborist", :project_id=>"4fad5bd7", :id=>"77ec58b5"} missing required keys: [:vendor_arborist_id, :item_link_standard_id]

Only when I remove the url param entirely does it finally start working:

<%= form_for [@vendor, @item_link, Message.new], method: :post, remote: true do |f| %>

To add to the mystery, as if this isn't screwed up enough, the second set of routes I specified above work just fine with or without the URL specified and with or without the subclasses specified.

    <%= form_for [@vendor, @project, Design.new], url: vendor_project_designs_path, method: :post, remote: true do |f| %>

So I'm now completely confused as to what is going wrong. My models are all very basic, these are simple Rails 101-esque routes. I'll post any other details if anyone needs them to debug this, but I don't know where else to look. What the hell am I doing wrong???

Update:

So after continuing with the testing, it seems this works as well. I suppose I can move forward with this, but that doesn't explain why it works in the example above for Design, but fails in all the examples with Message. Overall, it seems something in Rails 4 is causing these route helpers to get screwed up, because these examples all behaved just fine in Rails 3.2 which I'm migrating over from.

Credit to: Rails 4 shallow routes resource form submission not working

<%= form_for Message.new, url: vendor_item_link_messages_path(@vendor, @item_link), method: :post, remote: true do |f| %>

Additional reading:
Rails 4 [Best practices] Nested resources and shallow: true

The Controller Method

This is the method that is rendering the view which contains my busted form helper. I tried nulling out the @project param in case the form helper was somehow automagically accessing it, but setting it to null doesn't seem to have any impact.

def show
  @vendor = Vendor.find_by_subdomain( params[:vendor_id] )
  @project = @vendor.projects.find( params[:project_id] )
  @item_link = @project.item_links.find( params[:id] )

  @item_link.increment!(:views)

  respond_to do |format|
    format.html
  end
end

Rake Routes Output

    vendor_item_link_messages GET      /:vendor_id/item_links/:item_link_id/messages(.:format)                                                              item_links/messages#index
                              POST     /:vendor_id/item_links/:item_link_id/messages(.:format)                                                              item_links/messages#create
 new_vendor_item_link_message GET      /:vendor_id/item_links/:item_link_id/messages/new(.:format)                                                          item_links/messages#new
edit_vendor_item_link_message GET      /:vendor_id/item_links/:item_link_id/messages/:id/edit(.:format)                                                     item_links/messages#edit
     vendor_item_link_message GET      /:vendor_id/item_links/:item_link_id/messages/:id(.:format)                                                          item_links/messages#show
                              PATCH    /:vendor_id/item_links/:item_link_id/messages/:id(.:format)                                                          item_links/messages#update
                              PUT      /:vendor_id/item_links/:item_link_id/messages/:id(.:format)                                                          item_links/messages#update
                              DELETE   /:vendor_id/item_links/:item_link_id/messages/:id(.:format)                                                          item_links/messages#destroy
Community
  • 1
  • 1
R. Yanchuleff
  • 323
  • 1
  • 15
  • Can you share the Controller `action` from which the failing view(with `form_for [@vendor, @item_link, Message.new]`) is rendered. – Kirti Thorat Mar 10 '14 at 20:09
  • @KirtiThorat I posted the controller method, not sure if that helps at all. There is a reference to `@project` but as I mentioned, I tried nulling that out and it didn't have much impact. – R. Yanchuleff Mar 10 '14 at 20:27
  • @R.Yanchuleff Are you sure that calling `@design.item_links.first` work's fine in every case? (Just a heads up) – Rafael Ramos Bravin Mar 10 '14 at 20:34
  • @RafaelRamosBravin It does in this specific test case. It should be `@item_link`, but I was using that syntax just to test with here because I was certain it would return a valid result. I'll correct the post to avoid confusion. – R. Yanchuleff Mar 10 '14 at 20:36
  • What happens when you render the view without specifying url in form_for? – Kirti Thorat Mar 10 '14 at 20:40
  • @KirtiThorat Since my models all employ STI, I have to declare the specific routes in routes.rb. As long as I do that, it works just fine when I don't specify the url. The problem with that though is that I don't want to have to specify duplicate routes in my routes.rb for every subclass on every model. Its tedious and repetitive since they all go to the parent controller anyway. – R. Yanchuleff Mar 10 '14 at 20:44
  • @KirtiThorat An example `<%= form_for [@vendor, @item_link, Message.new], method: :post, remote: true do |f| %>` this works. But I have to add this to my routes.rb `resources :vendor_arborists do resources :item_link_standards do resources :messages end end` – R. Yanchuleff Mar 10 '14 at 20:46
  • The issue seems to be that whatever Rails does behind the scenes when the url is **not** specified is different than just adding the params to the declared url. Because in my opinion, the results should be the same. – R. Yanchuleff Mar 10 '14 at 20:47
  • 1
    @R.Yanchuleff Looking at your solution all I can think is that Rails couldn't handle the three layers of Nested Resources along with your multiple STI tables structure. I mean, at the moment you simplified the url generation it worked just fine. (+1 for your effort) – Rafael Ramos Bravin Mar 10 '14 at 21:09
  • @R.Yanchuleff Is the `designs` table also STI structured? – Rafael Ramos Bravin Mar 10 '14 at 21:13
  • @RafaelRamosBravin Yes, so is Project. So from that perspective, Project/Design should behave in the same manner as ItemLink/Message. In either case, since I have a working solution I can move forward, but it makes me suspicious that I've moved outside of the "Rails Way" of doing things. Its uncharacteristically flaky for Rails which makes me think its a bug in Rails. – R. Yanchuleff Mar 10 '14 at 21:16
  • 1
    @R.Yanchuleff The cause of this error seems to be beyond my knowledge, but I dont think this routing complexity would cause you any serious problems. – Rafael Ramos Bravin Mar 10 '14 at 21:33

0 Answers0