Reputation: 1371
Hey all i'm building an app in Rails 4 Ruby 2.
I have recently nested a form In side of my Calls Show page I have added Ping (update) feature.
since I have completed the nesting... i can see the Ping in the show field the button to create a new Ping works, however i have since lost the ability to create a new call all together.
The Error I get is:
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
My Routes rb file:
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
my calls/pings controller: (The update form accessed through the shot.html.erb page)
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
and this is my calls controller (The original form)
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
I have no idea where i've gone wrong as i have never nested before and after going back trough a few tutorials on nesting i am still stuck.
Any help is greatly appreciated!
Thanks in advance!
EDIT #1:
Rake Routes Output for the affected scaffolds:
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
EDIT #2: Rails Server Output when clicking new call button:
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'
Edit #3: Error when using 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">
Upvotes: 0
Views: 91
Reputation: 1371
So i solved this little problem.. It was actually a pretty ridiculous issue.. Whe i created the nested controller, I had the controller open when I dragged and dropped the file into the calls folder under controllers..
What happened was although i was pointing to the calls/pings controller and even though rake routes was showing the appropriate routes, rails was still looking at the original pings controller..
as soon as i deleted the duplicate controller, all fell into place and began to work just fine.
Thanks all for your had work on trying to resolve this!
Upvotes: 0
Reputation: 814
If you update pings for call in call controller then you have to do this:-
Model Call.rb
has_many :pings
accepts_nested_attributes_for :pings
Permit nested attributes in call_params method and change new and create method in calls_contoller.rb like:-
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
If you want to add pings for call from ping controller then you can add by doing this:-
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
Upvotes: 1
Reputation: 261
I would try running rake routes
from the command line and see if any routes rails generates from routes.rb
match your error.
Posting relevant info from running rake routes
may be useful.
EDIT:
Try just new_call_ping_path
on line 459 instead of new_call_ping_path(@call)
.
EDIT 2:
Try new_call_ping_path(call_id: @call.id)
. The problem here is the URL generator is expecting the call_id
since in routes.rb
declares the format as follows: new_call_ping GET /calls/:call_id/pings/new(.:format)
.
Upvotes: 1