Search code examples
ruby-on-railsnestednested-form-for

Rails: Nested form_for Errors: 'ActionController::UrlGenerationError'


I am having trouble using the form_for correctly for my nested resources.

I have the following set up in my models:

team.rb

class Team < ApplicationRecord
  has_many :superheroes
  accepts_nested_attributes_for :superheroes
end

superhero.rb

class Superhero < ApplicationRecord
  belongs_to :team
end

My routes: routes.rb

Rails.application.routes.draw do

  root to: 'teams#index'

  resources :teams do
    resources :superheroes
  end

  get '/teams/:team_id/superheroes/:id', to: 'superheroes#show', as: 'team_superheros'

end

In '/app/views/superheroes/new.html.erb'

<%= form_for [@team, @superhero] do |f| %>
  <p>Name</p>
  <p><%= f.text_field :name %></p>
  <p>True Identity</p>
  <p><%= f.text_field :true_identity %></p>
  <p><%= f.submit 'SAVE' %></p>
<% end %>

Lastly, in superheroes_controller.rb

def new
  @team = Team.find_by_id(params[:team_id])
  @superhero = @team.superheroes.build
end

I think maybe my understanding of the nested form_for isn't correct. When I navigate to the new_superhero page I originally got the following error:

undefined method `team_superheros_path'

So I added the following redirection route to routes.rb:

get '/teams/:team_id/superheroes/:id', to: 'superheroes#show', as: 'team_superheros'

This leaves me with the "Errors: 'ActionController::UrlGenerationError'" message with the specific error:

No route matches {:action=>"show", :controller=>"superheroes", :team_id=>#<Team id: 1, name: "Watchmen", publisher: "DC", created_at: "2016-10-22 04:04:46", updated_at: "2016-10-22 04:04:46">} missing required keys: [:id]

I must just be using the form_for incorrectly. I can create superheroes in the console via: watchmen.superheroes.create(name:"The Comedian",true_identity:"Edward Blake") and when the page is generated my @superhero is a blank instance of that class.

Any help?


Solution

  • EDIT: It turned out to be an irregular plural situation. I updated the code below to show what worked overall.

    My routes: routes.rb

    Rails.application.routes.draw do
    
      root to: 'teams#index'
    
      resources :teams do
        resources :superheroes
      end
    
    end
    

    In '/app/views/superheroes/new.html.erb'

    <%= form_for [@team,@superhero] do |f| %>
      <p>Name</p>
      <p><%= f.text_field :name %></p>
      <p>True Identity</p>
      <p><%= f.text_field :true_identity %></p>
      <p><%= f.submit 'SAVE' %></p>
    <% end %>
    

    In superheroes_controller.rb

    def new
      @superhero = @team.superheroes.build
    end
    

    Turns out what I needed to do was create a migration to rename :superheros to :superheroes

    class RenameTable < ActiveRecord::Migration[5.0]
      def change
        rename_table :superheros, :superheroes
      end
    end
    

    And then add to inflections.rb:

    ActiveSupport::Inflector.inflections(:en) do |inflect|
      inflect.irregular 'superhero', 'superheroes'
    end
    

    That was doozy.