Routing error No route matches id nil (Rails) - ruby-on-rails

I'm getting the following error on a page that contains a link to credit/edit an object:
Routing Error
No route matches {:controller=>"connections", :action=>"edit", :id=>nil}
My app has user profile pages (#show action in users_controller.rb) with a link to create or edit an existing "connection" (a relationship between users like Facebook or LinkedIn). If the connection does not exist, the link will send the user to create a new connection. If the connection already exists, the link will send the user to edit the existing connection. My create functionality works fine. However, once the connection has been created, visiting the user page throws the routing error. It clearly does not like my link_to for the edit action.
Here is the link_to on the user page:
<% unless current_user == #user %>
<% if #contact.present? %>
<%= #user.first_name %> is your <%= #connection.description %> (<%= link_to "edit contact", { :controller => 'connections', :action => 'edit', :id => #connection.id} %> )
<% else %>
How do you know <%= #user.first_name %>? (<%= link_to "edit contact", { :controller => 'connections', :action => 'create', :user_id => #user.id }, :method => 'post' %> )
<% end %>
The error also specifically states that :id is set to nil (null). The problem must be here. How can I my app to refer to the correct connection? My instance variable should have done the trick.
Here's the connection controller:
class ConnectionsController < ApplicationController
def index
end
def update
#connection = current_user.connections.find(params[:id])
if #connection.update_attributes(params[:connection])
flash[:notice] = "Contact relationship updated"
render 'activities'
end
end
def edit
#connection = current_user.connections.find(params[:id])
end
def create
##user = User.find(params[:user_id])
#connection = current_user.connections.build(params[:connection])
#user = User.find(params[:user_id])
if #connection.save
flash[:success] = "Contact relationship saved!"
else
render #user
end
end
end
And here's the User controller show action (where the link_to exists):
def show
#user = User.find(params[:id])
#connection = current_user.connections.build(:otheruser_id => #user)
#contact = current_user.connections.where(user_id: current_user, otheruser_id: #user)
end
routes.rb:
authenticated :user do
root :to => 'activities#index'
end
root :to => "home#index"
devise_for :users, :controllers => { :registrations => "registrations" }
resources :users do
member do
get :following, :followers, :posts, :comments, :activities, :works, :contributions, :connections
end
end
resources :works do
resources :comments
end
resources :relationships, only: [:create, :destroy]
resources :posts
resources :activities
resources :reposts
resources :comments do
member do
put :toggle_is_contribution
end
end
resources :explore
resources :connections
Any ideas on how to fix the link_to? Thanks!
EDIT 1: relevant rake routes:
connections GET /connections(.:format) connections#index
POST /connections(.:format) connections#create
new_connection GET /connections/new(.:format) connections#new
edit_connection GET /connections/:id/edit(.:format) connections#edit
connection GET /connections/:id(.:format) connections#show
PUT /connections/:id(.:format) connections#update
DELETE /connections/:id(.:format) connections#destroy

Your problem is in:
#connection = current_user.connections.build(:otheruser_id => #user)
That instantiates a connection object and assigns it to #connection. This object hasn't been saved, therefore it doesn't have an id. Conceptually it's wrong too, how can you edit something that doesn't exist yet? If you want to send the user to create a new connection, Connections#new is what you're after.

Related

How to destroy model with values

I'm kind of new to rails. I have a model called follows that has to values (requestor and following). I am having trouble creating a button that destroys a select model with two values
<dt>User ID:</dt>
<dd><%= #user.id %></dd>
<dt>User email:</dt>
<dd><%= #user.email %></dd>
<% if Follow.where(:requestor => current_user.id, :following =>#user.id).present? %>
<%= button_to 'Unfollow', follow_url, method: :delete, class: "text-danger", data: { confirm: 'Are you sure?' } %>
<% else %>
<%= button_to "Follow", {:controller => 'follows', :action => 'create', :requestor => current_user.id, :following => #user.id}, {:method => :post} %>
<% end %>
The Follow button below in the else statement works, but I cannot figure out how to get the destroy button to work. I'm executing these buttons on the User show page instead of on the follow index.
def destroy
#follow.destroy
respond_to do |format|
format.html { redirect_to follows_url, notice: 'Follow was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_follow
#follow = Follow.find(params[:id])
end
# Only allow a list of trusted parameters through.
def follow_params
params.permit(:requestor, :following)
end
def require_permission
if Follow.find(params[:id]).user != current_user
redirect_to goals_url, flash: { error: "You do not have permission to do that."}
end
end
end
I keep getting couldn't find Follow with 'id' error. It deletes sometimes, but the majority of the time I get this error.
Routes. uses general format
require 'sidekiq/web'
Rails.application.routes.draw do
resources :follows
resources :accounts
resources :goals
resources :retirements
get '/users', to: 'users#index'
get '/user/:id', to: 'users#show', as: 'user'
resources :calculate_debts
get '/privacy', to: 'home#privacy'
get '/terms', to: 'home#terms'
authenticate :user, lambda { |u| u.admin? } do
mount Sidekiq::Web => '/sidekiq'
end
resources :notifications, only: [:index]
resources :announcements, only: [:index]
devise_for :users, controllers: { omniauth_callbacks: "users/omniauth_callbacks" }
root to: 'home#index'
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end
It deletes sometimes, but the majority of the time I get this error
If it works "sometimes" then my guess would be that you are not re-rendering your page after your delete, and you might end up clicking the "Unfollow" button twice on the same record, which will raise a RecordNotFound error like you showed.
Your html redirect seems fine but make sure you are also refreshing the page when the request is in json format.

how to send confirmation email using rails?

I'm trying to setup logic in a rails 4.2.0 app where a person has to confirm their user account before they can login to the site / rails app. Basically, I have a sign up form where a person can input an email / password and their signed up. During this process an email is sent to their address with a confirmation token that should provide a link for them to confirm their account. I'm not exactly sure how to use the confirmation token so it changes a boolean value in the DB from false to true. I'll post what I have implemented so far.
users_controller.rb
def create
#user = User.new(user_params)
if #user.save
# send confirmation email after user has been created.
#user.send_confirmation
session[:user_id] = #user.id
redirect_to root_url, notice: "Thank you for signing up!"
else
render "new"
end
end
def confirm
#user = User.find_by_confirmation_token!(params[:id])
if #user.update_attributes(confirmed: true)
redirect_to login_path
end
end
confirmation.text.erb
To confirm your account, click the URL below.
<%= user_url(#user.confirmation_token) %>
<%= url_for(controller: 'users', action: 'confirm') %>
If you did not request your account creation, just ignore this email and your account will not be created.
routes.rb
Rails.application.routes.draw do
resources :articles do
resources :comments
end
get 'resume' => 'resume#index'
get 'signup' => 'users#new'
get 'login' =>'sessions#new'
get 'logout' => 'sessions#destroy'
# the below route led to a rails routing error
# get 'confirm' => 'users/:confirmation_token#confirm'
resources :users
resources :sessions
resources :password_resets
# route to hopefully get confirmation link working :-/
match '/users/:confirmation_token', :to => 'users#confirm', via: [:post, :get]
# test route
match 'users/foo', :to => 'users#foo', via: [:post, :get]
root "articles#index"
# Added below route for correct "resumé" spelling
get 'resumé', :to =>"resume#index"
# get 'about#index'
get 'about' => 'about#index'
get 'contact' => 'contact#contact'
resources :about
resources :contact
match ':controller(/:action(/:id))(.:format)', via: [:post, :get]
I ended up separating the confirmation logic into it's own controller, i.e. away from the users_controller.rb This allowed me to add the following line to my routes.rb
resources :confirmations
which allowed me to edit the confirmation.text.erb and put the following link in the email message,
<%= edit_confirmation_url(#user.confirmation_token) %>
thus when a person receives an email to confirm their account, it routes to the edit action of the confirmation controller, which the edit action calls the update action, and confirms the account. The controller looks like the following,
confirmations_controller.rb
class ConfirmationsController < ApplicationController
def new
end
def edit
#user = User.find_by_confirmation_token!(params[:id])
update
end
def update
# #user = User.find_by_confirmation_token!(params[:id])
if #user.confirmation_sent_at < 2.hours.ago
redirect_to new_confirmation_path, :alert => "Confirmation has expired."
# elseif #user.update_attributes(params[:user])
elsif #user.update_attributes(confirmed: true)
redirect_to root_url, :notice => "Your account has been confirmed."
else
render :new
end
end
end

Destroy Action Acting Unusual

The application has: Clients, which has and belongs to many ActionItems, which has and belongs to many Clients. A user, chooses a client (a client they have as a customer), and adds action items (to do's) to that client. -- Like: User creates => "Email client about X topic," for client: Crayola LLC.
I've been instructed to nest resources like so, in routes:
resources :clients do
resources :action_items
end
So that I can get a URL like:
-http://localhost:3000/clients/42/action_items/11
To display the action items for a specific client.
However - deleting action items for that client, doesn't work. It's been trying to redirect me to the destroy action, on which I get:
undefined local variable or method `clients_action_items' for # <ActionItemsController:0x007febd0edf800>
Prior to this, the delete link, which uses the destroy action, was attempting to redirect me to the show page, on which I was getting:
No route matches [POST] "/clients/42/action_items/1"
Then I added: post '/clients/:client_id/action_items/:id' => 'action_items#destroy' to the routes file. (and now I get the undefined local variable or method clients_action_items' error.
Routes:
Rails.application.routes.draw do
get 'users/index'
get 'users/new'
get 'users/edit'
get 'users/delete'
get 'users/create'
patch 'users/create'
patch 'users/update'
get 'clients/index'
get 'clients/new'
get 'clients/edit'
get 'clients/delete' => 'clients#delete'
get 'clients/create'
patch 'clients/create'
patch 'clients/update'
post '/clients/:client_id/action_items/:id' => 'action_items#destroy'
get 'login', :to => "access#index"
resources :action_items
#/clients/13/action_items
resources :clients do
resources :action_items
end
#get 'home/index'
#get 'home/edit'
#
#get 'home/delete'
#get 'home/show'
root 'home#index'
#define, below **, is the URL we named categories/index. It is now localhost:3000/define
#get 'index' => 'questions#index'
#get 'questions/edit'
#get 'new' => 'questions#new'
#get 'questions/delete'
#post 'questions/destroy'
#get 'questions/show'
#post 'create' => 'questions#create'
match ':controller(/:action(/:id))', :via => [:get, :post]
# end
end
Action Items Controller:
class ActionItemsController < ApplicationController
# before_action :get_owner
def index
#action_items = ActionItem.all
#client = Client.find(params[:client_id])
end
def new
#action_items = ActionItem.new
# #action_items_client = #client.action_items.new
#client = Client.find(params[:client_id])
end
def create
# #action_item = ActionItem.new(action_items_params)
# if #action_item.save
# redirect_to(:action => 'show', :id => #action_item.id)
# #renders client individual page
# else
# redirect_to(:action => 'new')
# end
#client = Client.find(params[:client_id])
#action_item_client = #client.action_items.new(action_items_params)
if #action_item_client.save
redirect_to(:action => 'show', :id => #action_item_client.id, :client_id => #client.id)
else
redirect_to(:action => 'new')
end
end
def edit
#action_item = ActionItem.find(params[:id])
end
def update
#action_item = ActionItem.find(params[:id])
if #action_item.update_attributes(action_items_params)
redirect_to(:controller => 'action_items', :action => 'show', :id => #action_item.id)
flash[:notice] = "Updated"
else
render 'new'
end
end
def show
#client = Client.find(params[:id])
#action_item = ActionItem.find(params[:action_item_id])
end
def action_clients
#action_clients = ActionItem.Client.new
end
def delete
#action_item = #client.action_items.find(params[:client_id])
end
def destroy
# #action_items = #client.action_items.find(params[:id]).destroy
# redirect_to(:controller => 'action_items', :action => 'index')
item = clients_action_items.find(params[:client_id])
item.destroy
if params[:client_id]
redirect_to clients_action_items_path(params[:client_id])
else
redirect_to clients_action_items_path
end
end
private
def action_items_params
params.require(:action_item).permit(:purpose, :correspondence_method, :know_person, :contact_name_answer, :additional_notes)
end
# private
# def get_owner
# if params[:client_id].present?
# #owner = user.clients.find(params[:client_id])
# else
# #owner = user
# end
# end
end
Index view from which I am deleting an action item:
<%= link_to('New Action Item', :controller => 'action_items', :action => 'new') %></br>
<ol><% #action_items.each do |list| %>
<li>
Action Item for <%= #client.name %> is: <strong><%= list.correspondence_method %></strong> Client, about:
<strong><%= list.purpose %> </strong></li>
And you created some additional notes: <strong><%= list.additional_notes %></strong></br></br>
-- Crud Actions -- </br>
<%= link_to('New Action Item', :controller => 'action_items', :action => 'new') %></br>
<%= link_to('Edit Action Item', :controller => 'action_items', :action => 'edit', :id => list.id) %></br>
<%= link_to('Show Individual', :controller => 'action_items', :action => 'show', :id => list.id) %></br>
<%= button_to('Delete Action Item', :controller => 'action_items', :action => 'destroy', :id => list.id) %></br>
<h2> new delete </h2>
</br></br>
<% end %></ol>
I have created the foreign key columns in a migration file with a join table called: action_items_clients:
class CreateActionItemsClients < ActiveRecord::Migration
def change
create_table :action_items_clients, :id => false do |t|
t.integer :action_item_id
t.integer :client_id
end
end
end
-New to rails. Please excuse dirty code. What is wrong here? Why the destroy link issues? Why was the destroy link redirecting to show before, and giving me both routing and ID errors?
Thanks for your time.
*** EDIT ****
Rake routes output:
Prefix Verb URI Pattern Controller#Action
users_index GET /users/index(.:format) users#index
users_new GET /users/new(.:format) users#new
users_edit GET /users/edit(.:format) users#edit
users_delete GET /users/delete(.:format) users#delete
users_create GET /users/create(.:format) users#create
PATCH /users/create(.:format) users#create
users_update PATCH /users/update(.:format) users#update
clients_index GET /clients/index(.:format) clients#index
clients_new GET /clients/new(.:format) clients#new
clients_edit GET /clients/edit(.:format) clients#edit
clients_delete GET /clients/delete(.:format) clients#delete
clients_create GET /clients/create(.:format) clients#create
PATCH /clients/create(.:format) clients#create
clients_update PATCH /clients/update(.:format) clients#update
DELETE /clients/:client_id/action_items/:id(.:format) action_items#destroy
login GET /login(.:format) access#index
action_items GET /action_items(.:format) action_items#index
POST /action_items(.:format) action_items#create
new_action_item GET /action_items/new(.:format) action_items#new
edit_action_item GET /action_items/:id/edit(.:format) action_items#edit
action_item GET /action_items/:id(.:format) action_items#show
PATCH /action_items/:id(.:format) action_items#update
PUT /action_items/:id(.:format) action_items#update
DELETE /action_items/:id(.:format) action_items#destroy
client_action_items GET /clients/:client_id/action_items(.:format) action_items#index
POST /clients/:client_id/action_items(.:format) action_items#create
new_client_action_item GET /clients/:client_id/action_items/new(.:format) action_items#new
edit_client_action_item GET /clients/:client_id/action_items/:id/edit(.:format) action_items#edit
client_action_item GET /clients/:client_id/action_items/:id(.:format) action_items#show
PATCH /clients/:client_id/action_items/:id(.:format) action_items#update
PUT /clients/:client_id/action_items/:id(.:format) action_items#update
DELETE /clients/:client_id/action_items/:id(.:format) action_items#destroy
clients GET /clients(.:format) clients#index
POST /clients(.:format) clients#create
new_client GET /clients/new(.:format) clients#new
edit_client GET /clients/:id/edit(.:format) clients#edit
client GET /clients/:id(.:format) clients#show
PATCH /clients/:id(.:format) clients#update
PUT /clients/:id(.:format) clients#update
DELETE /clients/:id(.:format) clients#destroy
root GET / home#index
GET|POST /:controller(/:action(/:id))(.:format) :controller#:action
It seems you are trying to destroy an object using a POST request.
No route matches [POST] "/clients/42/action_items/1"
Did you try a DELETE request?
delete '/clients/:client_id/action_items/:id' => 'action_items#destroy'
You can read further about CRUD (Create, Read, Update, Delete) operations here
Also, can you run rake:routes and post the output here? That will help figure out what routes are actually being generated.
EDIT
So, as you can see from the output of rake:routes there is a LOT of duplication. You basically have three models, User, Client and ActionItems with basic CRUD and one login.
Rake file:
Rails.application.routes.draw do
get 'login', :to => "access#index"
resources :users
resources :action_items
resources :clients do
member do
get :action_items
end
end
root 'home#index'
end
Client and ActionItems have a many-to-many relation. If it was a one-to-many ie many ActionItems belong to only one Client then it would have been better to nest the resources.
To show all action items of a client you only need one extra method in client controller.
Clients Controller:
def show
#client = Client.find(params[:id])
end
def action_items
#list_action_items = #client.action_items
end
Action Items Controller:
#Will list all action_items irrespective of which clients they belong to
def index
#action_items = ActionItem.all
end
#For creating a new action item,
def new
#action_item = ActionItem.new
#You can render a form with dropdown here with Client.all to assign the new action_item to a client
end
def create
#action_item = ActionItem.new(action_items_params)
if #action_item.save
redirect_to(:action => 'show', :id => #action_item.id)
#renders client individual page
else
redirect_to(:action => 'new')
end
end
def edit
#action_item = ActionItem.find(params[:id])
end
def update
if #action_item.update_attributes(action_items_params)
flash[:notice] = "Updated"
redirect_to(:controller => 'action_items', :action => 'show', :id => #action_item.id)
else
render 'new'
end
end
def show
#action_item = ActionItem.find(params[:id])
end
def destroy
#action_item.destroy
flash[:notice] = "Action Item has been deleted."
redirect_to action_items_path
end
I have tried to simplify the structure here. If you want to perform tasks like deleting all action items of a client from the index/list page of all clients, you can define a method destroy_many in the ActionItems controller which takes client_id as argument, queries all action items and deletes them.
You don't need separate ClientActionItem controller/routes.
Also, if you want to continue with nested routes,
try
<%= button_to('Delete Action Item', client_action_item_path(#client.id, list.id), method: :delete) %></br>
The nested route requires two arguments. The first is client.id and second the action_item id.
This should work, but un-tested. I am not sure of your intentions, but I would use a link_to with a class of button personally.
<%= button_to('Delete Action Item', client_action_item_path(#client, list), method: :delete) %></br>

No route matches {:action=>"edit", :controller=>"payments", :company_id=>#<Company id: 1 etc

So, I added the edit function to my payments controller, like this:
def edit
#payment = Payment.edit
if #payment.save
redirect_to showCompany_path, notice: 'Successfully edited!'
else
render :edit
end
end
I have a corresponding edit.html.haml view in my payments/view.
This is my routes rb:
resources :companies do
put :edit, :on => :collection
resources :payments do
put :edit, :on => :collection
end
end
And I want to have a link to this payments edit in my other view, which I defined like this:
<%= link_to 'Edit Payment Info', edit_company_payment_path(company), {:style=>'color:black; display:inline;', :class=>"btn btn-primary" } %>
I think I have done everything I should, but still I get this error from the title. Please help.
In order to generate a url to companies/:company_id/payments/:payment_id, Rails needs to know th e payment as well.
In other words, you are missing the payment param:
edit_company_payment_path(company, payment)
From your error, :company_id is an object not an integer. Try this,
edit_company_payment_path({:company_id => company.id, :payment_id => #payment.id})

routing with non rest actions

im having some trouble creating a route for my non restfull action in my controller, here is my code:
controller:
class StoresController < ApplicationController
def toggle_store
#store=Store.find(params[:store])
if #store.available==true
#store.update_attribute(:available, false)
else
#store.update_attribute(:available, true)
end
redirect_to #store
end
end
routes:
resources :groups do
resources :stores do
member do
post :toggle_store
end
end
end
but when i use the path in a link i get this url: http://example.com/groups/1/stores/toggle_store.2
and i need something like this:
http://example.com/groups/1/stores/2/toggle_store
any ideas?
Thanks
EDIT:
rake routes:
toggle_store_group_store POST /groups/:group_id/stores/:id/toggle_store(.:format) stores#toggle_store
Link:
<%=link_to "toggle", toggle_store_group_stores_path(#group,store), :method => :post %>
ok i fixed it like this:
routes.rb:
resources :groups do
resources :stores do
post :toggle_store
end
end
controller:
def toggle_store
authorize! :toggle, :store
#store=Store.find(params[:store_id])
if #store.available==true
#store.update_attribute(:available, false)
else
#store.update_attribute(:available, true)
end
redirect_to #group
end
link:
<%=link_to "to", toggle_store_group_store_path(#group,store), :method => :post %>

Resources