Destroying users as an admin in Devise - ruby-on-rails

I am trying to use Devise to delete users. I have a list of users each with their email and a 'delete' link next to them, only visible to me, the administrator. I want to be able to simply click the delete link to remove the user forever. The following code deletes me, the administrator!
<%= link_to "delete", user_registration_path, :method => :delete, :confirm => "You sure?" %>
I would think you need to pass the :id of the user you want to delete to some kind of 'destroy_user' method:
#user.find(params[:id]).destroy_user
But how do you do this when you have to submit a DELETE request to the user_registration_path??
------ EDIT --------
OK, I've added this method to my users controller:
def destroy
User.find(params[:id]).destroy
flash[:success] = "User destroyed."
redirect_to users_path
end
So, I need to tell the users controller to invoke the destroy method when it receives a DELETE request. How do you do this in routes.rb? Currently I have:
match '/users/:id', :to => 'users#show', :as => :user
match '/all_users', :to => 'users#index', :as => :all_users
I need something like:
match 'delete_user', :to => 'users#destroy', :as => :destroy_user, :method => :delete
but this doesn't work. And what should go in the link?:
<%= link_to "delete", destroy_user, :method => :delete, :confirm => "You sure?" %>
To put it another way, what should you put in the routes.rb file in order to distinguish between different request types (GET, DELETE etc) to the same url?

Replace 'user' by the actual user that you want to destroy, ex: if you're printing out the email as user.email, then plugin the user there et voilĂ 
<%= link_to "delete", user_registration_path(user), :method => :delete, :confirm => "You sure?" %>

Devise doesn't provide an action to delete another user, only to delete the currently logged in user. You'd have to create your own action in one of your controllers (most likely, whichever controller has the action to display all the users) to handle deleting a user other than the currently logged in one.

Got it! Simply needed to add the :via argument in routes:
match '/users/:id', :to => 'users#show', :as => :user, :via => :get
match '/users/:id', :to => 'users#destroy', :as => :destroy_user, :via => :delete

Related

Resources delete method not working with Devise

I am using devise gem for authentication. For the admin user I am trying to create a page where he will see the list of all users and will be able to delete them. Because devise does not provide action for delete I created a controller where I created destroy action.
controller:
def destroy
User.find(params[:id]).destroy
flash[:success] = "User destroyed."
redirect_to("/devise")
end
The view is simple, it just lists all users and posts a delete link next to them.
<% #users.each do |user| %>
<%= user.email %> <%= link_to 'Delete', :controller => :devise, :action => :destroy, :id => (user[:id]), method: :delete, data: { confirm: "Are you sure you want to delete this user permanently?" } %>
<% end %>
Up until this point it works - the page displays all users and the delete link too. However, when I try to delete random users it just opens them in new window instead of deleting them.
My routes are as follows:
Rails.application.routes.draw do
devise_for :admins
devise_for :users
resources :devise
resources :centres
resources :users
#match '/users/:id', :to => 'devise#show', :as => :user, :via => :get
match '/users/:id', :to => 'devise#destroy', :as => :destroy_user, :via => :delete
root 'welcome#index'
get '/index', to: 'welcome#index'
get '/about', to: 'welcome#about'
get '/help', to: 'welcome#help'
end
I need to make the delete function work. Thank you.
This is the solution for the question I posted:
controlled:
def destroy
User.find(params[:id]).destroy
flash[:success] = "User destroyed."
redirect_to("/users")
end
view:
<%= link_to "delete", user, method: :delete,
data: { confirm: "Are you sure you want to permanently delete this user?" } %>
route:
match '/users/:id', :to => 'users#destroy', :as => :destroy_user, :via => :delete
As far as i know, device doesn't handle destroy action. You should create a custom controller and provide a destroy action. In my case, i create a users_controller
users_controller:
def destroy
#user.destroy
respond_to do |format|
format.html { redirect_to users_url }
format.json { head :ok }
end
end
html.erb:
<%= link_to 'Delete', user, method: :delete, data: { confirm: 'Are you sure?' } %>
routes.rb:
match '/users/:id', :to => 'users#destroy', :as => :destroy_user, :via => :delete

How can I make /logout route to /login with method DELETE in Rails

Routes continue to be impenetrable to me. All I want is for the logout action to actually log someone out. Here is my attempt:
resource :login, controller: "sessions" do
collection do
get 'new'
get 'create'
end
end
match '/logout', :to => 'login', :controller => "sessions", :action => :destroy, :method => :delete
So you see I have this sessions controller, and I'm calling it "login". But that makes my link:
<%= link_to "Log Out", login_path, :method => :delete %>
I have no problem with that EXCEPT I am integrating with an outside site that uses my site as SSO. I need to provide a "logout" link to them. So I want it to just be "logout".
Can't you just make a logout action in your session controller and destroy the session there? Then your route can point to session#logout
Perhaps this is what you're looking for?
In routes.rb:
controller :sessions do
get 'login' => :new
post 'login' => :create
delete 'logout' => :destroy
end
For the logout link:
<%= link_to 'Logout', logout_path("current"), method: :delete %>

Devise/ Delete user Error

I am creating a form for an admin to go in and list, edit and delete users. I have tried many different variations for deleting a user and nothing works. I am wondering if it is because I need to use devise_for :users and resources :users in my routes.rb. This is because I have uploads/attachments linked to users. But here is my link
<%= link_to 'Delete',user, :method => 'delete', :confirm => 'Are you sure?' %>
And my routes.rb
# devise_for :users
devise_for :users do
get "/users/sign_out" => "devise/sessions#destroy", :as => :destroy_user_session
end
resources :users do
resources :attachments
end
The error I am receiving is The action 'destroy' could not be found for UsersController.
But my users controller has
def destroy
#user = User.find(params[:id]).destroy
redirect_to admin_index, :flash => { :success => 'User was successfully deleted.' }
end
If you are not using ajax for the requests, the problem is taht you ar using a link_to
In order to send the :method => 'delete' you have to use a button, jus like this:
<%= button_to 'Delete', user, :method => 'delete', :confirm => 'Are you sure?' %>
Because destructive action must be performed with a form submission:
http://www.w3.org/2001/tag/doc/whenToUseGet.html#checklist

Ruby routes and custom action

I'm trying to incorporate Devise and Cancan into a web app. I want users with :role => "admin" to be able to delete users, and Devise's destroy action only allows users to delete themselves, so I've created a custom action for this purpose. (To override the plugin's controller file, I've copied the registrations controller over to app/controllers/registrations_controller.rb.)
Here is my custom action in my registrations_controller.rb:
def destroy_user_account
#user = User.find_by_id(params[:user])
#user.destroy
redirect_to profiles_path, :flash => { :success => "User deleted!" }
authorize! :destroy, User, :message => "You don't have authorisation to delete this user."
end
Here is how I'm trying to use it, in a link on the page where you view a user's profile. (I have things set up so that each user has_one profile; profiles are what you see at the front end. A profile is automatically created in the profiles table on user registration.)
<% if can? :update, #profile %>
| <%= link_to 'Edit Profile', edit_profile_path(#profile) %>
| <%= link_to 'Edit Settings', edit_settings_path %>
<% end %>
<% if can? :destroy, #profile.user %>
| <%= link_to "Delete User", destroy_user_account(#profile.user),
:class => "delete",
:confirm => "Are you sure?",
:title => "Delete #{#profile.user.name}"
%>
<% end %>
My tests are showing 2 failures that I can't resolve:
1) ProfilesController GET show when signed in as an admin should
have a link to edit the profile
Failure/Error: get :show, :id => #profile
ActionView::Template::Error:
undefined method destroy_user_account' for #<#<Class:0x105b474a8>:0x1057f32e8>
# ./app/views/profiles/show.html.erb:41:in_app_views_profiles_show_html_erb___917863454_2195331000_0'
# ./spec/controllers/profiles_controller_spec.rb:143
2) ProfilesController GET show when signed in as an admin should
have a link to delete the user's account (using the
destroy_user_account action in the registrations controller)
Failure/Error: get :show, :id => #profile
ActionView::Template::Error:
undefined method destroy_user_account' for #<#<Class:0x105b474a8>:0x105806d20>
# ./app/views/profiles/show.html.erb:41:in_app_views_profiles_show_html_erb___917863454_2195331000_0'
# ./spec/controllers/profiles_controller_spec.rb:148
Also, when I try it out in my browser, clicking on the "Delete user" link gets me the following error:
Routing Error
No route matches "/destroy-user-account/2"
Here are the routes that should cover this:
devise_for :users, #:path => '',
:skip => [ :confirmations, :passwords, :registrations ],
:controllers => { :registrations => "registrations" } do
# Routes for ACCOUNT REGISTRATIONS
get "join", :to => "registrations#new", :as => :new_user_registration
post "join", :to => "registrations#create", :as => :user_registration
get "settings/account", :to => "registrations#show", :as => :settings
get "settings/account/edit", :to => "registrations#edit", :as => :edit_settings
put "settings/account", :to => "registrations#update", :as => :update_settings
delete "close-my-account/:id", :to => "registrations#destroy", :as => :close_my_account
delete "destroy-user-account/:id", :to => "registrations#destroy_user_account", :as => :destroy_user_account
Can anyone help with what I'm doing wrong?
In the browser it isn't matching the route because you're sending a GET request but the route only matches a DELETE request. The test fails because the route gives the name destroy_user_account_path instead of destroy_user_account.
Try:
<%= link_to "Delete User", destroy_user_account_path(#profile.user),
:class => "delete",
:confirm => "Are you sure?",
:title => "Delete #{#profile.user.name}"
:method => :delete
%>

Ruby routes and link_to, custom :action route problem

I'm trying to get this link:
<%= link_to('Edit', :action => 'manage', :id => user) %>
even tried explicitly <%= link_to('Edit', {:controller => 'users', :action => 'manage', :id => user}, :method => :get) %>
to show the link in HTML as
'/users/manage/1' or '/users/1/manage'
but it shows up as
'/users/manage?id=1'
I can see in my routes:
manage_users GET /users/manage(.:format) {:action=>"manage", :controller=>"users"}
...
edit_user GET /users/:id/edit(.:format) {:action=>"edit", :controller=>"users"}
so I added a map.connect, but it was added to users
users GET /users/manage/:id(.:format) {:action=>"manage", :controller=>"users"}
but without any success. The link is still '/users/manage?id=1'
This doesn't work anymore than the above.
GET /users/:id/manage(.:format) {:action=>"manage", :controller=>"users"}
Now, when I put the :action in link_to, to 'edit' i.e.
<%= link_to('Edit', :action => 'edit', :id => user) %>
The routes.rb edit_user GET /users/:id/edit/(.:format) works, with a link showing up of
'/users/1/edit'
How do I get my link_to to show the same link when it is 'manage' instead of 'edit', i.e. showing a link of 'users/1/manage' instead of '/users/manage?id=1'??? Is it because my above map.connect is being added to users, when it should be added to 'manage_users'?
Thank for the help. I'll be trying to figure it out.
Peace.
BTW, /users/manage?id=1 works, I just want the proper rewrite link to click on.
EDIT routes.rb
map.resources :users, :collection => {:manage => :get}
#map.manage_user '/users/:id/manage', :controller => :users, :action => :manage
#map.resources :users, :member => { :manage => :get }
#map.connect 'users/manage/:id(.:format)', :controller => 'users', :action => 'manage', :conditions => { :method => :get }
map.resources :categories
map.resources :posts
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
so I added a map.connect, but it was added to users
I suspect you added map.connect after other definitions, which would give it lowest priority. Try putting it in the beginning of routes.rb file.
You can also use named routes to avoid confusion:
map.manage_user '/users/:id/manage', :controller => :users, :action => :manage
and then refer it as
link_to 'Manage', manage_user_path(:id => user)
edit
If that doesn't work, please show your routes.rb file.
You should change collection to member in your routes.rb when defining map.resources :users. Then you'll get nice /users/1/manage link.
Also, when creating a link try this:
<%= link_to 'Manage', manage_user_path(user) %>

Resources