I recently watched the railscast episode #250 Authentication from Scratch (revised) and I have the signup / login / logout actions working. However I am working on creating an action to delete a user from the database, but I am currently experiencing some errors when I try to delete a user.
The users_controller.rb delete / destroy actions look like the following,
def delete
# the below line calls the destroy method / action
self.destroy
end
def destroy
session[:user_id] = nil
# #user = User.find(params[:id])
#user.destroy
# User.find(parmas[:id]).destroy
# the below line didn't delete the current user :(
# #user = User.destroy
redirect_to :controller=>'users', :action => 'new'
end
The error message I'm getting in the browser when I try to delete a user looks like the following.
The page that contains the delete link looks like the following, index.html.erb
<h1>Welcome
<% if current_user %>
<%= current_user.email %>
<% end %>
</h1>
<p>You have <%= current_user.credit %> credits.</p>
<!-- http://stackoverflow.com/questions/5607155/ -->
<%= link_to('Delete your account', :controller => 'users', :action => 'destroy') %>
routes.rb
Rails.application.routes.draw do
# the below generated route is not necessary
# get 'sessions/new'
# delete user route
#get 'delete' => 'users#delete'
# shortened routes, per railscast comment
get 'signup' => 'users#new'
get 'login' => 'sessions#new'
get 'logout' => 'sessions#destroy'
# get 'signup', to: 'users#new', :as 'signup'
# get 'login', to: 'sessions#new', :as 'login'
# get 'logout', to: 'sessions#destroy', :as 'logout'
resources :users
resources :sessions
root to: 'users#new'
# get 'users/new'
# the below line specifies JSON as the default API format
namespace :api, defaults: {format: 'json'} do
namespace :v1 do
resources :users
end
end
It stands to reason you're getting a NoMethodError, since you've never set the #user variable, that line is commented out:
def destroy
session[:user_id] = nil
# #user = User.find(params[:id]) <-- Commenting out this line was your problem
#user.destroy
Changing to
def destroy
session[:user_id] = nil
#user = User.find(params[:id])
#user.destroy
You should be good to go.
EDIT: one thing you'd probably want to do is change from using the old style of link_to, specifying the controller and action, and change to the new style, using route helpers. In this case, you'd use, i believe, link_to 'Delete your account', current_user, :method => :delete, but you can check by running rake routes, where it will list the helpers available based on your routes.rb file.
Well, I think you should make things a bit simpler and start from the dummiest thing, that works. First of all, if you use your controller as a resource, there would not be a delete action there, only destroy.
def destroy
User.find(params[:id]).destroy
session[:user_id] = nil
redirect_to new_user_path
end
P.S. once again, I assume that you have set resources :users in your routes.rb.
If you have a bunch of get|post|put|delete routes instead, just make sure you point the redirect correctly.
Related
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
I have a model "User". I defined it in my routes.rb with resources :users. I want to be able to render different versions of the same user. To see if it would work, here's what I tried in my routes.rb:
get "users/:id_alt", :to => "users#alt", :as => :user
and in my controller:
def show
#user = User.find(params[:id])
end
def alt
#user = User.find(params[:id])
end
But when I navigated to users/1, I got this error:
ActiveRecord::RecordNotFound in UsersController#alt
Couldn't find User without an ID
and the error pointed to this line under def alt:
#user = User.find(params[:id])
Anyone know how to remedy this error or accomplish this another way?
It is because you have set your route to use :id_alt
get "users/:id_alt", :to => "users#alt", :as => :user
So the controller is assuming the value in that location should have the name :id_alt not :id. You are not going to be able to have both routes set up this way, but you could do this:
get "users/alt/:id_alt", :to => "users#alt", :as => :alt_user
get "users/:id", :to => "users#show", :as => :user
You will be able to use these path methods: alt_user_path and user_path
And your controller should look like this:
def show
#user = User.find(params[:id])
end
def alt
#user = User.find(params[:id_alt])
render :show
end
Running rake routes will result in this:
alt_user GET /users/alt/:id_alt(.:format) users#alt
user GET /users/:id(.:format) users#show
I have two models for users ; the Plans model has_many users. Now, what I would like to do is to allow users to upgrade/downgrade their plans, by changing the plan_id. I've set up a form, as well as the appropriate action, but when I hit submit, it doesn't seem to do what the PUT action says. It seems to use the update action.
Here's my form :
<%= form_tag("/users/update_plan", :method => "put" ) do %>
<%= hidden_field_tag :plan_id, plan.id %>
<%= submit_tag("Change To Plan", :class => "signup") %>
<% end %>
Here's my update action
def update_plan
#user = current_user
#user.plan_id = params[:plan_id]
#user.save
sign_in #user
redirect_to change_plan
end
When I submit the form above though, it not only doesn't register the change, but I think it uses the update action, and not the update_plan action. The reason I think this is because it redirects to the what's in the update action, and it flashes the same thing as the update action.
def update
#user = current_user
if #user.update_attributes(params[:user])
flash[:success] = "Profile updated"
sign_in #user
redirect_to edit_user_path(#user)
else
render 'edit'
end
end
Here's my routes.rb file
Dentist::Application.routes.draw do
resources :users
resources :sessions, only: [:new, :create, :destroy]
resources :phones, only: [:new, :create, :destroy]
resources :find_numbers, only: [:new, :create, :destroy]
put 'users/update_plan'
match '/signup', to: 'users#new'
match '/login', to: 'sessions#new'
match '/signout', to: 'sessions#destroy', via: :delete
match '/change_plan', to: 'users#change_plan'
root to: 'static_pages#home'
match '/product_demo', to: 'static_pages#product_demo'
match '/pricing', to: 'plans#index'
match '/contact', to: 'static_pages#contact'
And here's a console screenshot of what's happening:
http://stepanp.com/debug3.jpg
It seems to say it's using the update_plan action, but... :S
Any help on trying to get Update_plan action to function would be greatly appreciated!
The form is going to the right place (/users/update_plan), but that is being routed to:
UsersController#update
as it says on the second line of your console log. So not the action you expect, and the problem is in your routes. Try this to list all your routes:
rake routes
Probably the users update route (created by resources :users) is catching this first:
PUT /users/:id(.:format) users#update
There are no restrictions on the content of id, and format is optional, so users/update_plan would call users/update with an id of update_plan (in fact you can see that is happening at the edge of your console log screenshot, look for the :id => parameter).
So I would move your custom route to the top of the routes file first above resources :users, and also try change it to direct to the action you want, not sure what a route with no action specified does...
put '/users/update_plan', to: 'users#update_plan'
i following happens, this is my Usercontroller
class UserController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
redirect_to user_session_path
else
redirect_to new_user_session_path
end
end
def show
#user = User.find(params[:id])
#redirect_to #user
end
end
in my routes.rb I have the following:
Estaciones::Application.routes.draw do
root :to => "static_pages#home"
match '/contact', :to=>'static_pages#contact'
match '/about', :to=>'static_pages#about'
devise_for :user
resources :user do
#resources :car
end
When I run it on my browser I get this:
Routing Error
No route matches {:action=>"show", :controller=>"user"}
Try running rake routes for more information on available routes.
I don't know why this happens???
You need to pass the User object or at least the user id to the link_to method where you're creating the link that you're clicking. Try something like <%= link_to user.name, user %>
Also make sure that your controller is properly named e.g. UsersController (plural).
Rename both the file:
'user_controller.rb' => 'users_controller.rb'
and the constant at the top:
UserController => UsersController
File names must match constants, and the convention is for models to be singular, and controllers to be plural (matching the table).
and try visiting
/users/1
I'm working through Ryan Bates' Railscast #124: Beta Invitations. I've got all the code in place, but I haven't been able to actually get things working. When I try to send an invite email, I get this message.
Routing Error
No route matches [POST] "/invitations"
If I pluralize the resource's name in Routes.rb, I get a different routing error.
Routing Error
uninitialized constant InvitationsController
What am I doing wrong?
Here's my Routes.rb file.
resources :users, :invitation
resources :sessions, :only => [:new, :create, :destroy]
match '/hunts', :to => 'hunts#index'
match '/signup/', :to => 'users#new'
match '/signin', :to => 'sessions#new'
match '/signout', :to => 'sessions#destroy'
match '/contact', :to => 'pages#contact'
match '/about', :to => 'pages#about'
match '/help', :to => 'pages#help'
root :to => "pages#home"
match ':controller(/:action(/:id(.:format)))'
end
And my Invitation Controller.
class InvitationController < ApplicationController
def new
#invitation = Invitation.new
end
def create
#invitation = Invitation.new(params[:invitation])
#invitation.sender = current_user
if #invitation.save
if logged_in?
Mailer.deliver_invitation(#invitation, signup_url(#invitation.token))
flash[:notice] = "Thank you, invitation sent."
redirect_to root_path
else
flash[:notice] = "Thank you, we will notify when we are ready."
redirect_to root_path
end
else
render :action => 'new'
end
end
end
Update: Here's the info requested.
Views/invitation/html.erb
<%= form_for #invitation do |f| %>
<p>
<%= f.label :recipient_email, "Friend's email address" %><br />
<%= f.text_field :recipient_email %>
</p>
<p><%= f.submit "Invite!" %></p>
<% end %>
rake routes is a very useful tool which you can use to see all the routes defined for your application.
You have added resources :invitation which defines the following routes
invitation_index GET /invitation(.:format) invitation#index
POST /invitation(.:format) invitation#create
new_invitation GET /invitation/new(.:format) invitation#new
edit_invitation GET /invitation/:id/edit(.:format) invitation#edit
invitation GET /invitation/:id(.:format) invitation#show
PUT /invitation/:id(.:format) invitation#update
DELETE /invitation/:id(.:format) invitation#destroy
Note that you are calling the InvitationController's actions.
So nothing is wrong with your route -> controller mapping.
You are just posting to a non-existent route. When you pluralize the route's name, you end up having a non-existent controller (InvitationsController).
Just change the URL you're posting to and you're good to go.
Try to use the plural when you call resources in your config/routes.rb:
resources :users, :invitations
This happens because you pass an instance of the Invitation model (#invitation) to this helper, it pluralize the class name to know where to submit.
Moreover, since #invitation is not yet saved in the DB (#invitation.new_record? returns true) then form_for set the form's method to "POST".
This information means the POST request to 'invitations' is processed by "invitations#create" (The create method of the InvitationsController class). It's convention over configuration, if you want to access invitations in a RESTful way and use resources in your config/routes.rb things must be named in a certain way to work out of the box (or you could simply override the "action" attribute of your form using some of the form helpers options).
BTW if you want to make things in a different manner you should read the Rails Guide to Routing and see if some option can help you to define your invitations routing rules, and have a look at the REST chapter of the Getting Started Rails Guide.
UPDATE: I missed the sentence "If I pluralize the resource's name in Routes.rb, I get a different routing error."
BTW, the problem is your controller class name is "InvitationController" while the form generated by the form_for helper submit to "/invitations".