【问题标题】:Issue with Nested Form Create - ActionController::UrlGenerationError in Calls#new嵌套表单创建问题 - Calls#new 中的 ActionController::UrlGenerationError
【发布时间】:2016-02-25 02:45:09
【问题描述】:

大家好,我正在使用 Rails 4 Ruby 2 构建应用程序。

我最近在我的通话显示页面中嵌套了一个表单,我添加了 Ping(更新)功能。

因为我已经完成了嵌套...我可以在显示字段中看到 Ping 按钮来创建一个新的 Ping 作品,但是我已经失去了一起创建一个新调用的能力。

我得到的错误是:

ActionController::UrlGenerationError in Calls#new
Showing /Users/TaurenLTD1/Desktop/TaurenLabs/PatrolProCAD/PatProCadApp/app/views/calls/_form.html.erb where line #459 raised:

No route matches {:action=>"new", :call_id=>nil, :controller=>"calls/pings"} missing required keys: [:call_id]
Extracted source (around line #459):
457
458
459
460
461
462

    </div>
    <div class="panel panel-info" id="update-pnl">
    <div class="panel-heading" id="update-top"><center><h4><strong id="update-txt">Live Updates - Found In View Call</strong> <%= link_to "Add Update", new_call_ping_path(@call), class: 'btn btn-primary btn-sm', :id => 'add-update' %> </h4></center></div>
    </div>
  <div class="new-wrapper">
    <div class="panel panel-warning" id="location-box">

Trace of template inclusion: app/views/calls/new.html.erb

我的路线 rb 文件:

Rails.application.routes.draw do

  devise_for :users, controllers: { registrations: 'registrations' }

  devise_scope :user do
    authenticated :user do
      root 'calls#index', as: :authenticated_root
    end

    unauthenticated do
      root 'devise/sessions#new', as: :unauthenticated_root
    end
  end

  resources :sites

  resources :calls do 
    resources :pings, except: [:index], controller: 'calls/pings'

    collection do
      get 'history'
    end

    member do
      patch :update_unit_on_scene
      patch :update_unit_clear
      patch :update_unit2_os
      patch :update_unit2_cl
      patch :update_unit3_os
      patch :update_unit3_cl
      patch :update_unit4_os
      patch :update_unit4_cl
    end
  end

end

我的呼叫/pings 控制器:(通过 shot.html.erb 页面访问的更新表单)

class Calls::PingsController < ApplicationController
  before_action :set_ping, only: [:show, :edit, :update, :destroy]

  # GET /pings
  # GET /pings.json
  def index
    @pings = Ping.all
  end

  # GET /pings/1
  # GET /pings/1.json
  def show

  end

  # GET /pings/new
  def new
    @call = Call.find(params[:call_id])
    @ping = Ping.new
  end

  # GET /pings/1/edit
  def edit

  end

  # POST /pings
  # POST /pings.json
  def create
    @call = Call.find(params[:call_id])
    @ping = Ping.new(ping_params)
    @ping.call = @call

    respond_to do |format|
      if @ping.save
        format.html { redirect_to @call, notice: 'Call update has been successfully added to call.' }
        format.json { render :show, status: :created, location: @call }
      else
        format.html { render :new }
        format.json { render json: @call.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /pings/1
  # PATCH/PUT /pings/1.json
  def update
    respond_to do |format|
      if @ping.update(ping_params)
        format.html { redirect_to @ping, notice: 'Ping was successfully updated.' }
        format.json { render :show, status: :ok, location: @ping }
      else
        format.html { render :edit }
        format.json { render json: @ping.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /pings/1
  # DELETE /pings/1.json
  def destroy
    @ping.destroy
    respond_to do |format|
      format.html { redirect_to pings_url, notice: 'Ping was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_ping
      @ping = Ping.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def ping_params
      params.require(:ping).permit(:priority, :msg, :received, :call_id)
    end
end

这是我的呼叫控制器(原始形式)

class CallsController < ApplicationController
  before_action :set_call, only: [:show, :edit, :update, :destroy]

  # GET /calls
  # GET /calls.json
  def index
    @calls = Call.all
    @active_calls = @calls.select{|x| x.status == 'ACTIVE'}
    @pending_calls = @calls.select{|x| x.status == 'PENDING'}
    @clear_calls = @calls.select{|x| x.status == 'CLEAR'}
    @approved_calls = @calls.select{|x| x.status == "APPROVED"}
    @on_scene = @calls.select{|x| x.status == "ACTIVE"}
  end

  # GET /calls/1
  # GET /calls/1.json
  def show
    @unit_2 = @call.unit_2
    @unit_3 = @call.unit_3
    @unit_4 = @call.unit_4

    @call = Call.find(params[:id])
    @pings = @call.pings
  end

  # GET /calls/new
  def new
    @call = Call.new

    @unit_2 = @call.unit_2
    @unit_3 = @call.unit_3
    @unit_4 = @call.unit_4

    @pings = @call.pings
  end

  # GET /calls/1/edit
  def edit
    @call = Call.find(params[:id])
  end

  # POST /calls
  # POST /calls.json
  def create
    @call = Call.new(call_params)

    @call = Call.find(params[:call_id])
    @ping = Ping.new(ping_params)
    @ping.call = @call


    respond_to do |format|
      if @call.save
        format.html { redirect_to @call, notice: 'Call was successfully created.' }
        format.json { render :show, status: :created, location: @call }
      else
        format.html { render :new }
        format.json { render json: @call.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /calls/1
  # PATCH/PUT /calls/1.json
  def update
    respond_to do |format|
      if @call.update(call_params)
        format.html { redirect_to @call, notice: 'Call was successfully updated.' }
        format.json { render :show, status: :ok, location: @call }
      else
        format.html { render :edit }
        format.json { render json: @call.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /calls/1
  # DELETE /calls/1.json
  def destroy
    @call.destroy
    respond_to do |format|
      format.html { redirect_to calls_url, notice: 'Call was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

### Custom View for Call History
  def history
    @approved_calls = Call.where(status: 'APPROVED')
  end

### Custom Calls for Unit 1-4 On Scene and Call Buttons ###
  def update_unit_on_scene
    @call = Call.find(params[:id])
    @call.unit_on_scene = DateTime.now
    @call.status = "ACTIVE"
    @call.save

    respond_to do |format|
      if @call.save
        format.html { redirect_to @call, notice: "On Scene Time Successfully Updated. - You Are Now Logged Out Of Service" }
      else
        format.html { render action: 'edit' }
      end
    end
  end

  def update_unit_clear
    @call = Call.find(params[:id])
    @call.unit_clear = DateTime.now
    @call.status = "CLEAR"
    @call.save

    respond_to do |format|
      if @call.save
        format.html { redirect_to @call, notice: "Scene Clear Time Successfully Updated. - You Are Now Logged In Service" }
      else
        format.html { render action: 'edit' }
      end
    end
  end

  def update_unit2_os
    @call = Call.find(params[:id])
    @call.unit2_os = DateTime.now
    @call.save

    respond_to do |format|
      if @call.save
        format.html { redirect_to @call, notice: "On Scene Time Successfully Updated. - You Are Now Logged Out Of Service" }
      else
        format.html { render action: 'edit' }
      end
    end
  end

  def update_unit2_cl
    @call = Call.find(params[:id])
    @call.unit2_cl = DateTime.now
    @call.save

    respond_to do |format|
      if @call.save
        format.html { redirect_to @call, notice: "Scene Clear Time Successfully Updated. - You Are Now Logged In Service" }
      else
        format.html { render action: 'edit' }
      end
    end
  end

  def update_unit3_os
    @call = Call.find(params[:id])
    @call.unit3_os = DateTime.now
    @call.save

    respond_to do |format|
      if @call.save
        format.html { redirect_to @call, notice: "On Scene Time Successfully Updated. - You Are Now Logged Out Of Service" }
      else
        format.html { render action: 'edit' }
      end
    end
  end

  def update_unit3_cl
    @call = Call.find(params[:id])
    @call.unit3_cl = DateTime.now
    @call.save

    respond_to do |format|
      if @call.save
        format.html { redirect_to @call, notice: "Scene Clear Time Successfully Updated. - You Are Now Logged In Service" }
      else
        format.html { render action: 'edit' }
      end
    end
  end

  def update_unit4_os
    @call = Call.find(params[:id])
    @call.unit4_os = DateTime.now
    @call.save

    respond_to do |format|
      if @call.save
        format.html { redirect_to @call, notice: "On Scene Time Successfully Updated. - You Are Now Logged Out Of Service" }
      else
        format.html { render action: 'edit' }
      end
    end
  end

  def update_unit4_cl
    @call = Call.find(params[:id])
    @call.unit4_cl = DateTime.now
    @call.save

    respond_to do |format|
      if @call.save
        format.html { redirect_to @call, notice: "Scene Clear Time Successfully Updated. - You Are Now Logged In Service" }
      else
        format.html { render action: 'edit' }
      end
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_call
      @call = Call.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def call_params
      params.require(:call).permit(:call_time, :status, :primary_type, :secondary_type, :site, :address, :unit_1, :unit_2, :unit_3, :unit_4, :call_details, :unit_on_scene, :unit_clear, :call_num, :site_id, :user_id, :unit2_os, :unit2_cl, :unit3_os, :unit3_cl, :unit4_os, :unit4_cl)
    end
end

我不知道我哪里出错了,因为我之前从未嵌套过,并且在通过一些关于嵌套的教程返回之后,我仍然卡住了。

非常感谢任何帮助!

提前致谢!

编辑#1:

受影响脚手架的 Rake Routes 输出:

     Prefix Verb   URI Pattern                                Controller#Action

               call_pings POST   /calls/:call_id/pings(.:format)            calls/pings#create
             new_call_ping GET    /calls/:call_id/pings/new(.:format)        calls/pings#new
            edit_call_ping GET    /calls/:call_id/pings/:id/edit(.:format)   calls/pings#edit
                 call_ping GET    /calls/:call_id/pings/:id(.:format)        calls/pings#show
                           PATCH  /calls/:call_id/pings/:id(.:format)        calls/pings#update
                           PUT    /calls/:call_id/pings/:id(.:format)        calls/pings#update
                           DELETE /calls/:call_id/pings/:id(.:format)        calls/pings#destroy
             history_calls GET    /calls/history(.:format)                   calls#history
 update_unit_on_scene_call PATCH  /calls/:id/update_unit_on_scene(.:format)  calls#update_unit_on_scene
    update_unit_clear_call PATCH  /calls/:id/update_unit_clear(.:format)     calls#update_unit_clear
      update_unit2_os_call PATCH  /calls/:id/update_unit2_os(.:format)       calls#update_unit2_os
      update_unit2_cl_call PATCH  /calls/:id/update_unit2_cl(.:format)       calls#update_unit2_cl
      update_unit3_os_call PATCH  /calls/:id/update_unit3_os(.:format)       calls#update_unit3_os
      update_unit3_cl_call PATCH  /calls/:id/update_unit3_cl(.:format)       calls#update_unit3_cl
      update_unit4_os_call PATCH  /calls/:id/update_unit4_os(.:format)       calls#update_unit4_os
      update_unit4_cl_call PATCH  /calls/:id/update_unit4_cl(.:format)       calls#update_unit4_cl
update_primary_resp_1_call PATCH  /calls/:id/update_primary_resp_1(.:format) calls#update_primary_resp_1
                     calls GET    /calls(.:format)                           calls#index
                           POST   /calls(.:format)                           calls#create
                  new_call GET    /calls/new(.:format)                       calls#new
                 edit_call GET    /calls/:id/edit(.:format)                  calls#edit
                      call GET    /calls/:id(.:format)                       calls#show
                           PATCH  /calls/:id(.:format)                       calls#update
                           PUT    /calls/:id(.:format)                       calls#update
                           DELETE /calls/:id(.:format)                       calls#destroy

编辑#2:点击新调用按钮时的 Rails 服务器输出:

tarted GET "/calls/new" for ::1 at 2015-11-22 23:26:21 -0700
Processing by CallsController#new as HTML
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1  ORDER BY "users"."id" ASC LIMIT 1  [["id", 3]]
  Rendered calls/_form.html.erb (11.8ms)
  Rendered calls/new.html.erb within layouts/application (13.4ms)
Completed 500 Internal Server Error in 19ms (ActiveRecord: 0.2ms)

ActionView::Template::Error (No route matches {:action=>"new", :call_id=>nil, :controller=>"calls/pings"} missing required keys: [:call_id]):
    456:       </table>
    457:     </div>
    458:     <div class="panel panel-info" id="update-pnl">
    459:     <div class="panel-heading" id="update-top"><center><h4><strong id="update-txt">Live Updates - Found In View Call</strong> <%= link_to "Add Update", new_call_ping_path(@call), class: 'btn btn-primary btn-sm', :id => 'add-update' %> </h4></center></div>
    460:     </div>
    461:   <div class="new-wrapper">
    462:     <div class="panel panel-warning" id="location-box">
  app/views/calls/_form.html.erb:459:in `block in _app_views_calls__form_html_erb___1493490319796568156_70162629771600'
  app/views/calls/_form.html.erb:1:in `_app_views_calls__form_html_erb___1493490319796568156_70162629771600'
  app/views/calls/new.html.erb:3:in `_app_views_calls_new_html_erb___3696559492073097692_70162629705900'

编辑 #3:使用 new_call_ping_path 时出错

ActionController::UrlGenerationError in Calls#edit
Showing /Users/TaurenLTD1/Desktop/TaurenLabs/PatrolProCAD/PatProCadApp/app/views/calls/_form.html.erb where line #459 raised:

No route matches {:action=>"new", :controller=>"calls/pings", :id=>"3"} missing required keys: [:call_id]

</div>
    <div class="panel panel-info" id="update-pnl">
    <div class="panel-heading" id="update-top"><center><h4><strong id="update-txt">Live Updates - Found In View Call</strong> <%= link_to "Add Update", new_call_ping_path, class: 'btn btn-primary btn-sm', :id => 'add-update' %> </h4></center></div>
    </div>
  <div class="new-wrapper">
    <div class="panel panel-warning" id="location-box">

【问题讨论】:

    标签: ruby ruby-on-rails-4 routes nested-forms


    【解决方案1】:

    我会尝试从命令行运行 rake routes 并查看 rails 从 routes.rb 生成的任何路由是否与您的错误匹配。

    发布运行 rake routes 的相关信息可能会有用。

    编辑:

    尝试仅在第 459 行使用 new_call_ping_path 而不是 new_call_ping_path(@call)

    编辑 2:

    试试new_call_ping_path(call_id: @call.id)。这里的问题是 URL 生成器需要 call_id,因为在 routes.rb 中声明格式如下:new_call_ping GET /calls/:call_id/pings/new(.:format)

    【讨论】:

    • 我很抱歉没有从命令行发布路由输出。现在已添加此内容。见编辑#1。我已经检查过了,在我看来没有什么不同。
    • 请参阅编辑#3 现在我收到此错误。您让我更改的路径是将新 ping 添加到呼叫中,但我的问题是我无法创建新呼叫。我确定它们是连接的……就像我说的我是嵌套的香草。对不起..尝试学习它..
    • 好的,我想我现在已经解决了。嵌套路由和链接生成器起初可能有点棘手。 This post 也很有帮助。
    • 仍然得到完全相同的错误...如果您想查看完整的上下文,我可以提交我必须提交的内容?
    • github.com/swilson223/PatProCad 是我的 Git 帐户,如果您想随意窥探。我知道有时这是最简单的方法。
    【解决方案2】:

    如果您在呼叫控制器中更新呼叫的 ping,那么您必须这样做:-

    模型调用.rb

    has_many :pings
    accepts_nested_attributes_for :pings
    

    在 call_params 方法中允许嵌套属性并在 call_contoller.rb 中更改 new 和 create 方法,如:-

    def new
        @call = Call.new
        @unit_2 = @call.unit_2
        @unit_3 = @call.unit_3
        @unit_4 = @call.unit_4
        @pings = @call.pings.build
    end
    
    def create
        @call = Call.new(call_params)
        respond_to do |format|
            if @call.save
                format.html { redirect_to @call, notice: 'Call was successfully created.' }
                format.json { render :show, status: :created, location: @call }
            else
                format.html { render :new }
                format.json { render json: @call.errors, status: :unprocessable_entity }
            end
    end
    
    private
    
    def call_params
        params.require(:call).permit(:call_time, :status, :primary_type, :secondary_type, :site, :address, :unit_1, :unit_2, :unit_3, :unit_4, :call_details, :unit_on_scene, :unit_clear, :call_num, :site_id, :user_id, :unit2_os, :unit2_cl, :unit3_os, :unit3_cl, :unit4_os, :unit4_cl,
                                     pings_attributes: [:id, :priority, :msg, :received])
    end
    

    如果您想为来自 ping 控制器的呼叫添加 ping,那么您可以通过以下方式添加:-

    def new
        @call = Call.find(params[:call_id])
        @pings = @call.pings.build
    end
    
    def create
        @call = Call.find(params[:call_id])
        respond_to do |format|
            if @call.update_attributes(call_params)
                format.html { redirect_to @call, notice: 'Call update has been successfully added to call.' }
                format.json { render :show, status: :created, location: @call }
            else
                format.html { render :new }
                format.json { render json: @call.errors, status: :unprocessable_entity }
            end
        end
    end
    
    private
    
    def call_params
        params.require(:call).permit(pings_attributes: [:id, :priority, :msg, :received])
    end
    

    【讨论】:

    • 所以第二种方式 -> 你是在引用调用/pings 控制器吗?我只是不知道哪个是哪个……我很抱歉。眼花缭乱..
    • 是的,我正在引用呼叫/pings 控制器。由于调用和 ping 之间存在关联,因此您需要从调用(如“@call.pings.build”)构建对象并为该调用创建 ping,而不是创建新的 ping 对象(如 Ping.new)。当您调用“@call.update_attributes(call_params)”时,它将添加/更新 pings 属性。
    【解决方案3】:

    所以我解决了这个小问题.. 这实际上是一个非常荒谬的问题.. 当我创建嵌套控制器时,当我将文件拖放到控制器下的调用文件夹中时,我打开了控制器..

    发生的事情是尽管我指向调用/pings 控制器,即使 rake 路由显示了适当的路由,rails 仍在查看原始 pings 控制器..

    一旦我删除了重复的控制器,一切都到位并开始正常工作。

    感谢大家为解决此问题所做的工作!

    【讨论】:

      猜你喜欢
      • 2015-10-30
      • 1970-01-01
      • 1970-01-01
      • 2015-05-23
      • 2016-10-30
      • 2017-03-04
      • 2015-12-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多