I'm trying to update a single databasefield of my current_user (devise).
I want to do this just with the link_to helper:
<%= link_to "Grid", edit_user_registration_path(current_user, :project_view => "grid"), :method => :put %>
But I can't get it to work since the result it allways an error:
Routing Error
No route matches [PUT] "/users/edit.1"
My Routes for Devise:
new_user_session GET /users/sign_in(.:format) devise/sessions#new
user_session POST /users/sign_in(.:format) devise/sessions#create
destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
user_password POST /users/password(.:format) devise/passwords#create
new_user_password GET /users/password/new(.:format) devise/passwords#new
edit_user_password GET /users/password/edit(.:format) devise/passwords#edit
PUT /users/password(.:format) devise/passwords#update
cancel_user_registration GET /users/cancel(.:format) devise/registrations#cancel
user_registration POST /users(.:format) devise/registrations#create
new_user_registration GET /users/sign_up(.:format) devise/registrations#new
edit_user_registration GET /users/edit(.:format) devise/registrations#edit
PUT /users(.:format) devise/registrations#update
DELETE /users(.:format) devise/registrations#destroy
What's wrong with the routing? I'm using devise without any custom modifications.
Thanks!
Wrong path helper:
$ rake routes
new_user_registration GET ... registrations#new
cancel_user_registration GET ... registrations#cancel
user_registration POST ... registrations#create
edit_user_registration GET ... registrations#edit
users PUT ... registrations#update # You want this one
DELETE ... registrations#destroy
Result:
<%= link_to "Grid", users_path(:user => {:project_view => 'grid'}), :method => :put, :confirm => "Are you sure?" %>
Update for your specific routes:
<%= link_to "Grid", registration_path(resource_name, :user => {:project_view => 'grid'}), :method => :put, :confirm => "Are you sure?" %>
I'm really starting to cry here ;) Trying to make a link in a Models index view.
I have 2 simple Models: Users and Posts. There both generated with scaffolding and have working joins. A user has_many :posts and a post belongs_to :user.
What I'm trying to do in the views/post/index.html.er file is a list of the Post title and the user who it belongs to. It works well (also learning html5):
<% #posts.each do |post| %>
<p><%= link_to post.user.name, users_path %>: <b><%= post.title %></b></p>
<% end %>
Well, it works but the "users_path" is not what I want. I want to link to the specific User which the post belongs_to. I'm sorry to say that I don't get much help from http://guides.rubyonrails.org/routing.html.
How should I do this? Do I have to specify a #user in the posts_controller index-action? I reallt appreciate long and detaild answears here.
Tnk soooo much for patience with a beginner ;)
you probably have this in your routes -
resources :posts do
resources :users
end
rake routes would generate the following mapping -
post_users GET /posts/:post_id/users(.:format) {:action=>"index", :controller=>"users"}
POST /posts/:post_id/users(.:format) {:action=>"create", :controller=>"users"}
new_post_user GET /posts/:post_id/users/new(.:format) {:action=>"new", :controller=>"users"}
edit_post_user GET /posts/:post_id/users/:id/edit(.:format) {:action=>"edit", :controller=>"users"}
post_user GET /posts/:post_id/users/:id(.:format) {:action=>"show", :controller=>"users"}
PUT /posts/:post_id/users/:id(.:format) {:action=>"update", :controller=>"users"}
DELETE /posts/:post_id/users/:id(.:format) {:action=>"destroy", :controller=>"users"}
posts GET /posts(.:format) {:action=>"index", :controller=>"posts"}
POST /posts(.:format) {:action=>"create", :controller=>"posts"}
new_post GET /posts/new(.:format) {:action=>"new", :controller=>"posts"}
edit_post GET /posts/:id/edit(.:format) {:action=>"edit", :controller=>"posts"}
post GET /posts/:id(.:format) {:action=>"show", :controller=>"posts"}
PUT /posts/:id(.:format) {:action=>"update", :controller=>"posts"}
DELETE /posts/:id(.:format) {:action=>"destroy", :controller=>"posts"}
The above explains the url you can use and what objects need to be passed.
For linking the user of the post -
<%= link_to "Post User details", post_user_path(post, post.user) %>
OR
<%= link_to "Post User details", url_for([post, post.user]) %>
I'm using Devise in a Rails 3 app, but in this case, a user must be created by an existing user, who determines what permissions he/she will have.
Because of this, I want:
To remove the route for users to sign up.
To still allow users to edit their profiles (change email address and password) after they have signed up
How can I do this?
Currently, I'm effectively removing this route by placing the following before devise_for :users:
match 'users/sign_up' => redirect('/404.html')
That works, but I imagine there's a better way, right?
Update
As Benoit Garret said, the best solution in my case is to skip creating the registrations routes en masse and just create the ones I actually want.
To do that, I first ran rake routes, then used the output to re-create the ones I wanted. The end result was this:
devise_for :users, :skip => [:registrations]
as :user do
get 'users/edit' => 'devise/registrations#edit', :as => 'edit_user_registration'
put 'users' => 'devise/registrations#update', :as => 'user_registration'
end
Note that:
I still have :registerable in my User model
devise/registrations handles updating email and password
Updating other user attributes - permissions, etc - is handled by a different controller
Actual answer:
Remove the route for the default Devise paths; i.e.:
devise_for :users, path_names: {
sign_up: ''
}
you can do this in your model
# typical devise setup in User.rb
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable
change it to:
devise :database_authenticatable, :recoverable, :rememberable, :trackable, :validatable
notice that the symbol :registerable was removed
That's it, nothing else is required. All routes and links to registration page are magically removed too.
I tried to do this as well, but a thread on the devise google group dissuaded me from searching for a really clean solution.
I'll quote José Valim (the Devise maintainer) :
There isn't a straight-forward option. You can either provide a patch
or use :skip => :registerable and add only the routes you want.
The original question was :
Is there any good way to remove a specific route (the delete route)
from Rails?
I had similar issue tried to remove devise_invitable paths for create and new :
before:
devise_for :users
rake routes
accept_user_invitation GET /users/invitation/accept(.:format) devise/invitations#edit
user_invitation POST /users/invitation(.:format) devise/invitations#create
new_user_invitation GET /users/invitation/new(.:format) devise/invitations#new
PUT /users/invitation(.:format) devise/invitations#update
after
devise_for :users , :skip => 'invitation'
devise_scope :user do
get "/users/invitation/accept", :to => "devise/invitations#edit", :as => 'accept_user_invitation'
put "/users/invitation", :to => "devise/invitations#update", :as => nil
end
rake routes
accept_user_invitation GET /users/invitation/accept(.:format) devise/invitations#edit
PUT /users/invitation(.:format) devise/invitations#update
note 1 devise scope https://github.com/plataformatec/devise#configuring-routes
note 2 I'm applying it on devise_invitable but it will work with any devise *able feature
Important note: see that devise_scope is on user not users ? that's correct, watch out for this ! It can cause lot of pain giving you this problem:
Started GET "/users/invitation/accept?invitation_token=xxxxxxx" for 127.0.0.1
Processing by Devise::InvitationsController#edit as HTML
Parameters: {"invitation_token"=>"6Fy5CgFHtjWfjsCyr3hG"}
[Devise] Could not find devise mapping for path "/users/invitation/accept? invitation_token=6Fy5CgFHtjWfjsCyr3hG".
This may happen for two reasons:
1) You forgot to wrap your route inside the scope block. For example:
devise_scope :user do
match "/some/route" => "some_devise_controller"
end
2) You are testing a Devise controller bypassing the router.
If so, you can explicitly tell Devise which mapping to use:
#request.env["devise.mapping"] = Devise.mappings[:user]
I found another post similar to this one and wanted to share an answer #chrisnicola gave. In the post they were attempting to only block user signup's during production.
You could also modify the registrations controller. You can use something like this:
In "app/controllers/registrations_controller.rb"
class RegistrationsController < Devise::RegistrationsController
def new
flash[:info] = 'Registrations are not open.'
redirect_to root_path
end
def create
flash[:info] = 'Registrations are not open.'
redirect_to root_path
end
end
This will override devise's controller and use the above methods instead. They added flash messages incase that someone somehow made it to the sign_up page. You should also be able to change the redirect to any path you like.
Also in "config/routes.rb" you can add this:
devise_for :users, :controllers => { :registrations => "registrations" }
Leaving it like this will allow you to use the standard devise edit your profile. If you wish you can still override the edit profile option by including
def update
end
in the "app/controllers/registrations_controller.rb"
This is an old question - but I recently had solve the same issue and came up with a solution which is far more elegant than:
devise_for :users, :skip => [:registrations]
as :user do
get 'users/edit' => 'devise/registrations#edit', :as => 'edit_user_registration'
put 'users' => 'devise/registrations#update', :as => 'user_registration'
end
And it gives the default names for the named routes (like cancel_user_registration) without being excessively verbose.
devise_for :users, skip: [:registrations]
# Recreates the Devise registrations routes
# They act on a singular user (the signed in user)
# Add the actions you want in 'only:'
resource :users,
only: [:edit, :update, :destroy],
controller: 'devise/registrations',
as: :user_registration do
get 'cancel'
end
rake routes output with the default devise modules:
Prefix Verb URI Pattern Controller#Action
new_user_session GET /users/sign_in(.:format) devise/sessions#new
user_session POST /users/sign_in(.:format) devise/sessions#create
destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
user_password POST /users/password(.:format) devise/passwords#create
new_user_password GET /users/password/new(.:format) devise/passwords#new
edit_user_password GET /users/password/edit(.:format) devise/passwords#edit
PATCH /users/password(.:format) devise/passwords#update
PUT /users/password(.:format) devise/passwords#update
cancel_user_registration GET /users/cancel(.:format) devise/registrations#cancel
edit_user_registration GET /users/edit(.:format) devise/registrations#edit
user_registration PATCH /users(.:format) devise/registrations#update
PUT /users(.:format) devise/registrations#update
DELETE /users(.:format) devise/registrations#destroy
You can override the "devise_scope" by placing it before the "devise_for".
devise_scope :user do
get "/users/sign_up", :to => "sites#index"
end
devise_for :users
Not sure if this is the best way but its my solution currently, as it just redirects back to the sign in page.
I liked #max's answer, but when trying to use it I ran into an error due to devise_mapping being nil.
I modified his solution slightly to one that seems to address the issue. It required wrapping the call to resource inside devise_scope.
devise_for :users, skip: [:registrations]
devise_scope :user do
resource :users,
only: [:edit, :update, :destroy],
controller: 'devise/registrations',
as: :user_registration do
get 'cancel'
end
end
Note that devise_scope expects the singular :user whereas resource expects the plural :users.
Do This in routes.rb
devise_for :users, :controllers => {:registrations => "registrations"}, :skip => [:registrations]
as :user do
get 'users/edit' => 'devise/registrations#edit', :as => 'edit_user_registration'
put 'users' => 'devise/registrations#update', :as => 'user_registration'
end
devise_scope :user do
get "/sign_in", :to => "devise/sessions#new"
get "/sign_up", :to => "devise/registrations#new"
end
you will get an error now while you come to sign in page, to fix it.
Do this change in: app/views/devise/shared/_links.erb
<% if request.path != "/sign_in" %>
<%- if devise_mapping.registerable? && controller_name != 'registrations' %>
<%= link_to "Sign up", new_registration_path(resource_name) %><br />
<% end -%>
<% end %>
I've found this to work well without messing with routes or adding application controller methods. My approach is to override the devise method. Add this to app/controllers/devise/registrations_controller.rb
I've omitted the other methods for brevity.
class Devise::RegistrationsController < DeviseController
...
# GET /resource/sign_up
def new
redirect_to root_path
end
....
end
Also to remove illusion that this path is still reachable from other views you might also want to remove this code from app/views/devise/shared/_links.erb
<%- if devise_mapping.registerable? && controller_name != 'registrations' %>
<%= link_to "Sign up", new_registration_path(resource_name) %><br />
<% end -%>
For others in my case.
With devise (3.5.2).
I successfully removed the routes to signup, but kept the ones to edit the profile, with the following code.
#routes.rb
devise_for :users, skip: [:registrations]
as :user do
get 'users/edit' => 'devise/registrations#edit', :as => 'edit_user_registration'
put '/users(.:format)' => 'devise/registrations#update', as: 'user_registration'
patch '/users(.:format)' => 'devise/registrations#update'
end
Here's the slightly different route I went. It makes it so you don't have to override the devise/shared/_links.html.erb view.
In app/models/user.rb:
devise :database_authenticatable, :recoverable, :rememberable, :trackable, :validatable
In config/routes.rb:
devise_for :users
devise_scope :user do
put 'users' => 'devise/registrations#update', as: 'user_registration'
get 'users/edit' => 'devise/registrations#edit', as: 'edit_user_registration'
delete 'users' => 'devise/registrations#destroy', as: 'registration'
end
Before:
$ rake routes | grep devise
new_user_session GET /users/sign_in(.:format) devise/sessions#new
user_session POST /users/sign_in(.:format) devise/sessions#create
destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
user_password POST /users/password(.:format) devise/passwords#create
new_user_password GET /users/password/new(.:format) devise/passwords#new
edit_user_password GET /users/password/edit(.:format) devise/passwords#edit
PATCH /users/password(.:format) devise/passwords#update
PUT /users/password(.:format) devise/passwords#update
cancel_user_registration GET /users/cancel(.:format) devise/registrations#cancel
user_registration POST /users(.:format) devise/registrations#create
new_user_registration GET /users/sign_up(.:format) devise/registrations#new
edit_user_registration GET /users/edit(.:format) devise/registrations#edit
PATCH /users(.:format) devise/registrations#update
PUT /users(.:format) devise/registrations#update
DELETE /users(.:format) devise/registrations#destroy
After:
$ rake routes | grep devise
new_user_session GET /users/sign_in(.:format) devise/sessions#new
user_session POST /users/sign_in(.:format) devise/sessions#create
destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
user_password POST /users/password(.:format) devise/passwords#create
new_user_password GET /users/password/new(.:format) devise/passwords#new
edit_user_password GET /users/password/edit(.:format) devise/passwords#edit
PATCH /users/password(.:format) devise/passwords#update
PUT /users/password(.:format) devise/passwords#update
user_registration PUT /users(.:format) devise/registrations#update
edit_user_registration GET /users/edit(.:format) devise/registrations#edit
registration DELETE /users(.:format) devise/registrations#destroy
Instead of searching for a hard solution. I used the below approaches.
Delete the sign_up form from page (path devise/registrations/new.html.erb) and replace it with custom info.
Redirect the incoming traffic to some other page. Like below in routes.rb
get "/users/sign_up", to: redirect('/')
post "/users/sign_up", to: redirect('/')
Make sure to write it before devise_for :users
I had the same issue and I found it a bit bad practise to redirect users from the registration page. So my solution is basically is not using :registrable at all.
What I did was to create a similar page like edit user details which looked like:
<%= form_tag(update_user_update_path, method: :post) do %>
<br>
<%= label_tag(:currPassword, 'Current password:') %> <%= password_field_tag(:currPassword) %> <br>
<%= label_tag(:newPassword, 'New password:') %> <%= password_field_tag(:newPassword) %> <br>
<%= label_tag(:newPasswordConfirm, 'Confirm new password:') %> <%= password_field_tag(:newPasswordConfirm) %> <br>
<%= submit_tag('Update') %>
<% end %>
So this form submits into a new post end point that updates the password, which looks like:
def update
currPass = params['currPassword']
newPass1 = params['newPassword']
newPass2 = params['newPasswordConfirm']
currentUserParams = Hash.new()
currentUserParams[:current_password] = currPass
currentUserParams[:password] = newPass1
currentUserParams[:password_confirmation] = newPass2
#result = current_user.update_with_password(currentUserParams)
end
Later on you can use the #result in your view to tell the user whether the password is updated or not.
By changing the routes there are a whole bunch of other problems that come with that. The easiest method I have found is to do the following.
ApplicationController < ActionController::Base
before_action :dont_allow_user_self_registration
private
def dont_allow_user_self_registration
if ['devise/registrations','devise_invitable/registrations'].include?(params[:controller]) && ['new','create'].include?(params[:action])
redirect_to root_path
end
end
end
You could modify the devise gem itself. First, run this command to find the installed location of using:
gem which devise
Let's suppose the path is:
/usr/local/lib/ruby/gems/1.9.1/gems/devise-1.4.2/lib/devise
Then go to
/usr/local/lib/ruby/gems/1.9.1/gems/devise-1.4.2/lib/devise/lib/devise/rails and edit routes.rb in that directory. There is a method called def devise_registration(mapping, controllers) which you can modify to get rid of the new action. You can also completely remove the mappings for devise_registration
I am using resources :users in routes.rb. This provides the following paths as rake routes unveils.
users GET /users(.:format) {:action=>"index", :controller=>"users"}
POST /users(.:format) {:action=>"create", :controller=>"users"}
new_user GET /users/new(.:format) {:action=>"new", :controller=>"users"}
edit_user GET /users/:id/edit(.:format) {:action=>"edit", :controller=>"users"}
user GET /users/:id(.:format) {:action=>"show", :controller=>"users"}
PUT /users/:id(.:format) {:action=>"update", :controller=>"users"}
DELETE /users/:id(.:format) {:action=>"destroy", :controller=>"users"}
Further, I comment out the legacy wild controller route.
#match ':controller(/:action(/:id(.:format)))'
To add a delete link on my users page I add the following.
<%= link_to "Delete user", user, :method => :delete, :confirm => "Are you sure?" %>
This generated the following html code.
Delete user
I click the link and it takes me to the show page?! What's wrong?
You need to include the default Javascript files for that to work properly:
<%= javascript_include_tag :defaults %>
I'm trying to add a link so the user can destroy his/her own account. I'm using the built-in registration class.
In my view I have <%= link_to 'Destroy', current_user, :confirm => 'Are you sure you want to destroy your account?', :method => :delete %> pointing to localhost:3000/users/4 by example
First of all, is that the correct link to use?
Secondly, how to redirect to root path because presently it looks like it tries to redirect to user with id 4 (and it fails because it is protected).
Rake routes gives DELETE /users(.:format) {:action=>"destroy", :controller=>"devise/registrations"}
Thanks in advance.
Try
<%= link_to 'Destroy', user_registration_path, :confirm => 'Are you sure you want to destroy your account?', :method => :delete %>
It's because of devise treat registration as Singular Resource.
Besides, run rake routes and you can see details about registration routing:
user_registration POST /users(.:format) {:action=>"create", :controller=>"devise/registrations"}
new_user_registration GET /users/sign_up(.:format) {:action=>"new", :controller=>"devise/registrations"}
edit_user_registration GET /users/edit(.:format) {:action=>"edit", :controller=>"devise/registrations"}
user_registration PUT /users(.:format) {:action=>"update", :controller=>"devise/registrations"}
user_registration DELETE /users(.:format) {:action=>"destroy", :controller=>"devise/registrations"}
It means:
user_registration_path is a helper method that returns /users(.format)
Perform DELETE request on /users(.format) will delete the registration