【问题标题】:edit path for nested resource throws error missing required keys: [:id]嵌套资源的编辑路径抛出错误缺少必需的键:[:id]
【发布时间】:2020-09-20 12:27:14
【问题描述】:

我查看了几个不同的类似 SO 帖子并尝试了解决方案,但没有一个对我有用,而且我已经坚持了几天了。我认为我的应用程序可能有其他问题导致了这个问题。

问题: 我需要创建一个链接来编辑联系人的地址。我知道该路由需要两个 ID,但我无法弄清楚为什么我提供的变量无法像在 destroy 方法链接中那样提供地址 ID。这篇文章可能有问题: 或者也许是我的控制器的编辑方法之一。我想不通。我很感激任何帮助。为任何愚蠢的错误道歉,我对此很陌生。

错误:

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" = $1 LIMIT $2  [["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" = $1  [["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

views/contacts/show.html/erb

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

耙路线:

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)                      

【问题讨论】:

    标签: ruby-on-rails link-to


    【解决方案1】:

    错误从这里开始:

      def show
        @contact = Contact.find(params[:id])
        @address = @contact.addresses.new
      end
    

    调用@contact.addresses.new 会创建一个新的Address 模型,该模型与您的@contact 相关联。全新的Address还没有 ID。即使@contact 已经保存了地址,您也正在这样做。因此,当您开始迭代时:

    <% @contact.addresses.each do |address| %>
    

    一旦点击未保存的Address,它将创建一个带有nil ID 的链接;单击将不起作用。

    删除未使用的@address = @contact.addresses.new 行将使页面正常工作,但表中还没有任何地址。如果您正在尝试测试,您可以随时将指向该联系页面的链接添加到 new_contact_address_path(@contact) 以创建一个新链接!

    更新:要继续在页面上使用@address 作为表单,您可以从Address 的角度创建它:

    @address = Address.new(contact: @contact)
    

    这将分配新的@address 您当前的@contact 开始,但它不会修改@contact 的地址列表,这是您想要的。

    【讨论】:

    • 非常感谢,这很有道理!不幸的是,我需要那行代码来使我的地址形成部分功能: 如果我删除它,我会得到错误,“undefined method `model_name' for nil:NilClass” 你能用另一种方式在 show 方法中定义@address 而不破坏表单吗?我在contacts/show.html.erb文件和addresses/edit.html.erb中将变量作为局部变量传递
    • 非常感谢!经过几天的奋斗,你真的帮了我很多。我要去下一个错误:)
    【解决方案2】:

    当您使用循环时:

    &lt;% @contact.addresses.each do |address| %&gt; 我猜address 之一缺少id 值。

    尝试在 Rails 控制台中检查:Contact.find(16).addresses.pluck(:id)。我相信您会在结果数组中找到nil 值。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多