嵌套资源的编辑路径抛出错误,缺少必需的键:[:id]
edit path for nested resource throws error missing required keys: [:id]
我查看了几个不同的类似 SO 帖子并尝试了解决方案,但是 none 对我有用,我已经坚持了几天了。我认为我的应用程序可能还有其他问题导致了这个问题。
问题:
我需要创建 link 来编辑联系人地址。我知道路由需要两个 ID,但我无法弄清楚为什么我提供的变量无法像在 destroy 方法 link 中那样提供地址 ID。这篇文章可能有问题:
<%= link_to 'Edit Address', edit_contact_address_path(address.contact, 地址) %>
或者我的控制器的一种编辑方法中的某些东西。我想不通。我感谢任何帮助。对于任何愚蠢的错误,我深表歉意,我对此很陌生。
错误:
Started GET "/contacts/16/" for ::1 at 2020-09-20 14:02:46 +0200
Processing by ContactsController#show as HTML
Parameters: {"id"=>"16"}
Contact Load (13.8ms) SELECT "contacts".* FROM "contacts" WHERE "contacts"."id" = LIMIT [["id", 16], ["LIMIT", 1]]
↳ app/controllers/contacts_controller.rb:8:in `show'
Rendering contacts/show.html.erb within layouts/application
Address Load (6.3ms) SELECT "addresses".* FROM "addresses" WHERE "addresses"."contact_id" = [["contact_id", 16]]
↳ app/views/contacts/show.html.erb:21
Rendered contacts/show.html.erb within layouts/application (Duration: 11.3ms | Allocations: 2127)
Completed 500 Internal Server Error in 33ms (ActiveRecord: 20.4ms | Allocations: 3488)
ActionView::Template::Error (No route matches {:action=>"edit", :contact_id=>"16", :controller=>"addresses", :id=>nil}, missing required keys: [:id]):
28: <td><%= address.zip %></td>
29: <td><%= address.state %></td>
30: <td><%= address.country %></td>
31: <td><%= link_to 'Edit Address', edit_contact_address_path(address.contact, address) %></td>
32: <td><%= link_to 'Destroy Address', [address.contact, address],
33: method: :delete,
34: data: { confirm: 'Are you sure?' } %></td>
app/views/contacts/show.html.erb:31
app/views/contacts/show.html.erb:21
routes.rb
Rails.application.routes.draw do
resources :contacts do
resources :addresses
end
root to: 'welcome#index'
end
models/address.rb
class Address < ApplicationRecord
validates :street, :town, :zip, :country, presence: true
belongs_to :contact
end
models/contact.rb
class Contact < ApplicationRecord
has_many :addresses, dependent: :destroy
validates :first_name, presence: true
validates :last_name, presence: true
end
[...excerpt...]
<% if @contact.addresses.any? %>
<h2>Addresses</h2>
<% @contact.addresses.each do |address| %>
<% debug address.id %>
<table>
<tr>
<td><%= address.id %></td>
<td><%= address.street %></td>
<td><%= address.town %></td>
<td><%= address.zip %></td>
<td><%= address.state %></td>
<td><%= address.country %></td>
<td><%= link_to 'Edit Address', edit_contact_address_path(address.contact, address) %></td>
<td><%= link_to 'Destroy Address', [address.contact, address],
method: :delete,
data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
<% end %>
controllers/contacts_controller.rb
class ContactsController < ApplicationController
[...excerpt...]
def show
@contact = Contact.find(params[:id])
@address = @contact.addresses.new
end
controllers/addresses_controller.rb
class AddressesController < ApplicationController
[...excerpt...]
def new
@contact = Contact.find(params[:contact_id])
@address = Address.new
end
def edit
@contact = Contact.find(params[:contact_id])
@address = @contact.addresses.find(params[:id])
end
rake 路线:
contact_addresses GET /contacts/:contact_id/addresses(.:format) addresses#index
POST /contacts/:contact_id/addresses(.:format) addresses#create
new_contact_address GET /contacts/:contact_id/addresses/new(.:format) addresses#new
edit_contact_address GET /contacts/:contact_id/addresses/:id/edit(.:format) addresses#edit
contact_address GET /contacts/:contact_id/addresses/:id(.:format) addresses#show
PATCH /contacts/:contact_id/addresses/:id(.:format) addresses#update
PUT /contacts/:contact_id/addresses/:id(.:format) addresses#update
DELETE /contacts/:contact_id/addresses/:id(.:format) addresses#destroy
contacts GET /contacts(.:format) contacts#index
POST /contacts(.:format) contacts#create
new_contact GET /contacts/new(.:format) contacts#new
edit_contact GET /contacts/:id/edit(.:format) contacts#edit
contact GET /contacts/:id(.:format) contacts#show
PATCH /contacts/:id(.:format) contacts#update
PUT /contacts/:id(.:format) contacts#update
DELETE /contacts/:id(.:format)
当您使用循环时:
<% @contact.addresses.each do |address| %>
我猜 address
之一缺少 id
值。
尝试在 rails 控制台中检查:Contact.find(16).addresses.pluck(:id)
。我相信您会在结果数组中找到一个 nil
值。
错误从这里开始:
def show
@contact = Contact.find(params[:id])
@address = @contact.addresses.new
end
调用 @contact.addresses.new
会创建一个绑定到您的 @contact
的新 Address
模型。全新的 Address
还没有 ID。即使 @contact
已经保存了地址,您仍在执行此操作。因此,当您开始迭代时:
<% @contact.addresses.each do |address| %>
一旦找到未保存的 Address
,它将创建一个 link 和 nil
ID;单击将不起作用。
删除未使用的 @address = @contact.addresses.new
行将使页面正常工作,尽管 table 中还没有任何地址。如果您正在尝试测试,您可以随时将 link 添加到该联系页面到 new_contact_address_path(@contact)
以创建一个新联系页面!
更新:要继续使用@address
作为页面上的表单,您可以从Address
:
的角度创建它
@address = Address.new(contact: @contact)
这会将新的 @address
分配给您当前的 @contact
,但它不会修改 @contact
的地址列表,这正是您想要的。
我查看了几个不同的类似 SO 帖子并尝试了解决方案,但是 none 对我有用,我已经坚持了几天了。我认为我的应用程序可能还有其他问题导致了这个问题。
问题: 我需要创建 link 来编辑联系人地址。我知道路由需要两个 ID,但我无法弄清楚为什么我提供的变量无法像在 destroy 方法 link 中那样提供地址 ID。这篇文章可能有问题: <%= link_to 'Edit Address', edit_contact_address_path(address.contact, 地址) %> 或者我的控制器的一种编辑方法中的某些东西。我想不通。我感谢任何帮助。对于任何愚蠢的错误,我深表歉意,我对此很陌生。
错误:
Started GET "/contacts/16/" for ::1 at 2020-09-20 14:02:46 +0200
Processing by ContactsController#show as HTML
Parameters: {"id"=>"16"}
Contact Load (13.8ms) SELECT "contacts".* FROM "contacts" WHERE "contacts"."id" = LIMIT [["id", 16], ["LIMIT", 1]]
↳ app/controllers/contacts_controller.rb:8:in `show'
Rendering contacts/show.html.erb within layouts/application
Address Load (6.3ms) SELECT "addresses".* FROM "addresses" WHERE "addresses"."contact_id" = [["contact_id", 16]]
↳ app/views/contacts/show.html.erb:21
Rendered contacts/show.html.erb within layouts/application (Duration: 11.3ms | Allocations: 2127)
Completed 500 Internal Server Error in 33ms (ActiveRecord: 20.4ms | Allocations: 3488)
ActionView::Template::Error (No route matches {:action=>"edit", :contact_id=>"16", :controller=>"addresses", :id=>nil}, missing required keys: [:id]):
28: <td><%= address.zip %></td>
29: <td><%= address.state %></td>
30: <td><%= address.country %></td>
31: <td><%= link_to 'Edit Address', edit_contact_address_path(address.contact, address) %></td>
32: <td><%= link_to 'Destroy Address', [address.contact, address],
33: method: :delete,
34: data: { confirm: 'Are you sure?' } %></td>
app/views/contacts/show.html.erb:31
app/views/contacts/show.html.erb:21
routes.rb
Rails.application.routes.draw do
resources :contacts do
resources :addresses
end
root to: 'welcome#index'
end
models/address.rb
class Address < ApplicationRecord
validates :street, :town, :zip, :country, presence: true
belongs_to :contact
end
models/contact.rb
class Contact < ApplicationRecord
has_many :addresses, dependent: :destroy
validates :first_name, presence: true
validates :last_name, presence: true
end
[...excerpt...]
<% if @contact.addresses.any? %>
<h2>Addresses</h2>
<% @contact.addresses.each do |address| %>
<% debug address.id %>
<table>
<tr>
<td><%= address.id %></td>
<td><%= address.street %></td>
<td><%= address.town %></td>
<td><%= address.zip %></td>
<td><%= address.state %></td>
<td><%= address.country %></td>
<td><%= link_to 'Edit Address', edit_contact_address_path(address.contact, address) %></td>
<td><%= link_to 'Destroy Address', [address.contact, address],
method: :delete,
data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
<% end %>
controllers/contacts_controller.rb
class ContactsController < ApplicationController
[...excerpt...]
def show
@contact = Contact.find(params[:id])
@address = @contact.addresses.new
end
controllers/addresses_controller.rb
class AddressesController < ApplicationController
[...excerpt...]
def new
@contact = Contact.find(params[:contact_id])
@address = Address.new
end
def edit
@contact = Contact.find(params[:contact_id])
@address = @contact.addresses.find(params[:id])
end
rake 路线:
contact_addresses GET /contacts/:contact_id/addresses(.:format) addresses#index
POST /contacts/:contact_id/addresses(.:format) addresses#create
new_contact_address GET /contacts/:contact_id/addresses/new(.:format) addresses#new
edit_contact_address GET /contacts/:contact_id/addresses/:id/edit(.:format) addresses#edit
contact_address GET /contacts/:contact_id/addresses/:id(.:format) addresses#show
PATCH /contacts/:contact_id/addresses/:id(.:format) addresses#update
PUT /contacts/:contact_id/addresses/:id(.:format) addresses#update
DELETE /contacts/:contact_id/addresses/:id(.:format) addresses#destroy
contacts GET /contacts(.:format) contacts#index
POST /contacts(.:format) contacts#create
new_contact GET /contacts/new(.:format) contacts#new
edit_contact GET /contacts/:id/edit(.:format) contacts#edit
contact GET /contacts/:id(.:format) contacts#show
PATCH /contacts/:id(.:format) contacts#update
PUT /contacts/:id(.:format) contacts#update
DELETE /contacts/:id(.:format)
当您使用循环时:
<% @contact.addresses.each do |address| %>
我猜 address
之一缺少 id
值。
尝试在 rails 控制台中检查:Contact.find(16).addresses.pluck(:id)
。我相信您会在结果数组中找到一个 nil
值。
错误从这里开始:
def show
@contact = Contact.find(params[:id])
@address = @contact.addresses.new
end
调用 @contact.addresses.new
会创建一个绑定到您的 @contact
的新 Address
模型。全新的 Address
还没有 ID。即使 @contact
已经保存了地址,您仍在执行此操作。因此,当您开始迭代时:
<% @contact.addresses.each do |address| %>
一旦找到未保存的 Address
,它将创建一个 link 和 nil
ID;单击将不起作用。
删除未使用的 @address = @contact.addresses.new
行将使页面正常工作,尽管 table 中还没有任何地址。如果您正在尝试测试,您可以随时将 link 添加到该联系页面到 new_contact_address_path(@contact)
以创建一个新联系页面!
更新:要继续使用@address
作为页面上的表单,您可以从Address
:
@address = Address.new(contact: @contact)
这会将新的 @address
分配给您当前的 @contact
,但它不会修改 @contact
的地址列表,这正是您想要的。