rails3: action being routed to the wrong controller. Possible bug? - ruby-on-rails-3

I have two models (user & profile) with a 1-to-1 association.
class Profile < ActiveRecord::Base
attr_accessible :language_tokens, :tele, :languages, :serviceDesc, :service
belongs_to :user
...
class User < ActiveRecord::Base
has_one :profile, dependent: :destroy
The profile is built using:
#profile = #user.build_profile(session[:form_params])
my profile edit form is just a standard form which should be routed to my profile update action upon submission.
<%= form_for #profile do |f| %>
<%= render 'shared/host_information', :f => f%>
<%= render 'shared/service_information', :f => f%>
<%= f.submit 'done', class: "bnt"%>
<% end %>
HTML form:
<form id="edit_profile_6" class="edit_profile" method="post" action="/profiles/6" accept-charset="UTF-8">
However, for some bizarre reason, the form is being submitted to user update instead of the expected profile update. I put a debug point in user update and you can see that the params confirm that the target controller should indeed be profiles_controller.
/railsapp/loco_app/app/controllers/users_controller.rb:82
#user = User.find_by_id(params[:id])
(rdb:15) p params
{"utf8"=>"✓", "_method"=>"put", "authenticity_token"=>"qXx5EWwIWASiARKVFE7eDd43gHnBSmK538YAXeesDyI=", "profile"=>{"country_id"=>"8", "city_id"=>"22", "tele"=>"", "language_tokens"=>"18,14", "service"=>"9", },
"commit"=>"done", "action"=>"update", "controller"=>"profiles", "id"=>"6"}
(rdb:15)
here are the relevant routes:
profiles POST /profiles(.:format) profiles#create
new_profile GET /profiles/new(.:format) profiles#new
edit_profile GET /profiles/:id/edit(.:format) profiles#edit
profile PUT /profiles/:id(.:format) profiles#update
users GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
What's the best way to debug this problem? Is this some weird side-effect of a 1-to-1 association or is there a bug here? I'm using rails 3.2.2.
*UPDATE*
So this definitely looks like a bug. I regenerated my controller (same name) and copied over the same code and now it's working without any other changes. I'm still interested in knowing whether this is a known issue and how to debug problems like this in the future.

Related

Which is the best practice in trying to get the edit and update actions to work with before_action filters and strong params

I'm new to rails and am working on a simple reddit-type app for practice. I'm trying to let users update the link they have posted. This is the links_controller:-
class LinksController < ApplicationController
before_action :logged_in_user, only: [:new, :create, :edit, :update]
#before_action :correct_user, only: [:edit, :update]
def new
#link = Link.new
end
def create
#user = current_user
#link = #user.links.build(params)
if #link.save
flash[:success]= "Link submittd successfully"
redirect_to root_path
else
flash[:danger]= "Link submission failed"
render 'new'
end
end
def edit
#user = current_user
#link = #user.links.find_by(id: params[:id])
end
def update
#user = current_user
#link = #user.links.find_by(id: params[:id])
if #link.update_attributes(params)
flash[:success] = "Link successfully edited"
redirect_to current_user
else
flash[:danger] = "Link edit failed"
render 'edit'
end
end
private
# def link_params
# params.permit(:title, :url)
# end
def logged_in_user
redirect_to login_path unless logged_in
end
def correct_user
#link = current_user.links.find_by(id: params[:id])
redirect_to root_path if #link.nil?
end
end
Currently I'm facing this error:-
Log:-
Started GET "/edit_link" for ::1 at 2017-05-23 13:20:56 +0530
Processing by LinksController#edit as HTML
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
Link Load (0.2ms) SELECT "links".* FROM "links" WHERE "links"."user_id" = ? AND "links"."id" IS NULL ORDER BY "links"."created_at" DESC LIMIT ? [["user_id", 1], ["LIMIT", 1]]
Rendering links/edit.html.erb within layouts/application
Rendered links/edit.html.erb within layouts/application (4.6ms)
Completed 500 Internal Server Error in 70ms (ActiveRecord: 1.6ms)
ActionView::Template::Error (First argument in form cannot contain nil or be empty):
4: <div class="row">
5: <div class="col-md-6 col-md-offset-3">
6:
7: <%= form_for(#link, url: edit_link_path) do |f| %>
8:
9: <%= f.label :title %>
10: <%= f.text_field :title, class: 'form-control' %>
This is the edit form for the link:-
<% provide(:title, 'Edit Link') %>
<h1>Edit Link</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for(#link, url: edit_link_path) do |f| %>
<%= f.label :title %>
<%= f.text_field :title, class: 'form-control' %>
<%= f.label :url %>
<%= f.text_field :url, class: 'form-control' %>
<%= f.submit "Save Changes", class: "btn btn-primary" %>
<% end %>
</div>
</div>
The routes file:-
Rails.application.routes.draw do
root 'static_pages#home'
get '/login', to: 'sessions#new'
post '/login', to: 'sessions#create'
delete '/logout', to: 'sessions#destroy'
get '/signup', to: 'users#new'
post '/signup', to: 'users#create'
get '/submit_link', to: 'links#new'
post '/submit_link', to: 'links#create'
get '/edit_link', to: 'links#edit'
patch '/edit_link', to: 'links#update'
get '/contact', to: 'static_pages#contact'
resources :users
resources :links
end
As it stands it is really messy. There are many different things that could be wrong and I don't have enough grasp over the various factors to find out the best way to do this.
I'm especially struggling with the params, strong params.
Basically this is what I'm trying to implement:-
Only logged in user who is the owner of the link can access the edit
and update actions for the link. I'm using the before_action filters
to ensure this.
I'm using strong params as defined in the link_params method in
private
I'm not 100% sure on the code in the edit and update actions. What I've listed up there is just what I think should be the logical code.
If you could show me how to get this to work and also the best practice to be followed while doing this, it would be great.
Update:-
I tried to use link_params earlier but that seemed to generate the error of the required link not being present, so I have muted it for now and am trying to work out how to get it to work through params first.
As it stands it seems that the edit and update actions are not receiving the params[:id] that is required for them to proceed with the action. I don't know how to get the params to be accessible in the actions. I've used the custom route get "edit_link_path" for the links#edit and patch "edit_link_path" for the links#update. Don't know if this is a problem.
Most recent update:-
updated routes.rb (with the link.id appendage to edit and update routes):-
Rails.application.routes.draw do
root 'static_pages#home'
get '/login', to: 'sessions#new'
post '/login', to: 'sessions#create'
delete '/logout', to: 'sessions#destroy'
get '/signup', to: 'users#new'
post '/signup', to: 'users#create'
get '/edit_link/link.id', to: 'links#edit'
patch '/edit_link/link.id', to: 'links#update'
get '/submit_link', to: 'links#new'
post '/submit_link', to: 'links#create'
get '/contact', to: 'static_pages#contact'
resources :users
resources :links
end
A list of all available routes:-
$ rails routes
Prefix Verb URI Pattern Controller#Action
root GET / static_pages#home
login GET /login(.:format) sessions#new
POST /login(.:format) sessions#create
logout DELETE /logout(.:format) sessions#destroy
signup GET /signup(.:format) users#new
POST /signup(.:format) users#create
GET /edit_link/link.id(.:format) links#edit
PATCH /edit_link/link.id(.:format) links#update
submit_link GET /submit_link(.:format) links#new
POST /submit_link(.:format) links#create
contact GET /contact(.:format) static_pages#contact
users GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
PATCH /users/:id(.:format) users#update
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
links GET /links(.:format) links#index
POST /links(.:format) links#create
new_link GET /links/new(.:format) links#new
edit_link GET /links/:id/edit(.:format) links#edit
link GET /links/:id(.:format) links#show
PATCH /links/:id(.:format) links#update
PUT /links/:id(.:format) links#update
DELETE /links/:id(.:format) links#destroy links#update
PUT /links/:id(.:format) links#update
DELETE /links/:id(.:format) links#destroy
Currently the error is No route matches [PATCH] "/links/2/edit"
As you can see above in the list of available routes, there is a "edit_link GET /links/:id/edit(.:format) links#edit" but there is no equivalent for the update action even though the routes.rb file has the listing for that. Don't understand why.
Ok, finally figured it out and fixed everything. The problem was with the routing. I had to route the link id in the routes for edit and update and it had to be patch '/link.:id'. Everything else including strong params and correct_user works after that. Great!

no route matches controller (Rails 3)

I'm pretty new to RoR, please help me identify where I am wrong
I get the following error
Routing Error
No route matches {:controller=>"groups"}
Try running rake routes for more information on available routes
when trying to render the following view
<li><%= link_to 'My groups', user_groups_path %></li>
<li><%= link_to 'New group', new_user_group_path %></li>
and here is 'routes.rb' and rake routes output
devise_for :users
resources :users do |user|
resources :groups do |group|
resources :people do |person|
end
end
end
new_user_session GET /users/sign_in(.:format) devise/sessions#new
user_session POST /users/sign_in(.:format) devise/sessions#create
destroy_user_session GET /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
user_group_people GET /users/:user_id/groups/:group_id/people(.:format) people#index
POST /users/:user_id/groups/:group_id/people(.:format) people#create
new_user_group_person GET /users/:user_id/groups/:group_id/people/new(.:format) people#new
edit_user_group_person GET /users/:user_id/groups/:group_id/people/:id/edit(.:format) people#edit
user_group_person GET /users/:user_id/groups/:group_id/people/:id(.:format) people#show
PUT /users/:user_id/groups/:group_id/people/:id(.:format) people#update
DELETE /users/:user_id/groups/:group_id/people/:id(.:format) people#destroy
groups GET /users/:user_id/groups(.:format) groups#index
POST /users/:user_id/groups(.:format) groups#create
new_user_group GET /users/:user_id/groups/new(.:format) groups#new
edit_user_group GET /users/:user_id/groups/:id/edit(.:format) groups#edit
user_group GET /users/:user_id/groups/:id(.:format) groups#show
PUT /users/:user_id/groups/:id(.:format) groups#update
DELETE /users/:user_id/groups/:id(.:format) groups#destroy
users GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
here is 'model.rb'
class User < ActiveRecord::Base
has_many :groups
class Group < ActiveRecord::Base
belongs_to :user
has_many :people
please help me figure out how to fix the problem
many thanks.
UPD
here is solution, it works
I made all changes suggested by #Abibullah and two changes in controllers
view:
<li><%= link_to 'My groups', user_groups_path(current_user) %></li>
<li><%= link_to 'New group', new_user_group_path(current_user) %></li>
routes.rb
resources :users do |user|
resources :groups do |group|
resources :people
end
end
devise_for :users
GroupsController.rb:
def index
#user = current_user
#user.groups = Group.all
was:
def index
#user = current_user
#groups = Group.all
end
UsersController.rb
class Devise::UsersController < DeviseController
def show
end
end
To Create a nested Group Inside User, U need to pass the user_id inside which U are Creating the Group.
For Ex: If I have user1
Then I will use the routes as this:
link_to 'My groups', user_groups_path(user1)
OR
link_to 'My groups', user_groups_path(user1.id)
AND
link_to 'My Group', new_user_group_path(user1)
OR
link_to 'My Group', new_user_group_path(user1.id)
This is to tell that, To which User you are creating the Group.
If U want to access any specific Group, say for ex: grp1
then My url will be
link_to 'My Group', user_group_path(user1, grp1)
THis is a good refrence for routing.
http://guides.rubyonrails.org/routing.html
I think it's obvious. You've got a typo in your
<li><%= link_to 'My groups', user_groups_path %></li>
link. The path should be user_group_path (without the 's') as shown in your rake routes output, instead of the one you've written in your link.

Rails App session error, can't signin

I'm creating my first solo project with rails and users can't seem to sign in. I call my sign in method immediately after the user is created, but if they sign out the app will not let them sign back in. Here is what I am getting when submitting the sign in form
Here is the error message
undefined method `[]' for nil:NilClass
it says it is in line 6 of the sessions controller but I think something else is wrong
Sessions Controller
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by_email(params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
sign_in user
redirect_to user
else
flash.now[:error] = 'Invalid email/password combination'
render 'new'
end
end
def destroy
sign_out
redirect_to root_path
end
end
Login form
<h1>Sign in</h1>
<br />
<%= form_tag sessions_path do %>
<%= label_tag :email %><br />
<%= text_field_tag :email %><br />
<%= label_tag :password %><br />
<%= text_field_tag :password %><br />
<%= submit_tag "Sign in", class: "button" %>
<% end %>
<p>New user? <%= link_to "Sign up now!", signup_path %></p>
Routes
Blog::Application.routes.draw do
get "sessions/new"
get "users/new"
resources :posts
resources :static_pages
resources :users
resources :sessions
root to: 'posts#index'
match '/signin', to: 'sessions#new'
match '/signup', to: 'users#new'
match '/signout', to: 'sessions#destroy', via: :delete
match '/about', to: 'static_pages#about'
match '/projects', to: 'static_pages#projects'
end
Also here is the rake:routes
sessions_new GET /sessions/new(.:format) sessions#new
users_new GET /users/new(.:format) users#new
posts GET /posts(.:format) posts#index
POST /posts(.:format) posts#create
new_post GET /posts/new(.:format) posts#new
edit_post GET /posts/:id/edit(.:format) posts#edit
post GET /posts/:id(.:format) posts#show
PUT /posts/:id(.:format) posts#update
DELETE /posts/:id(.:format) posts#destroy
static_pages GET /static_pages(.:format) static_pages#index
POST /static_pages(.:format) static_pages#create
new_static_page GET /static_pages/new(.:format) static_pages#new
edit_static_page GET /static_pages/:id/edit(.:format) static_pages#edit
static_page GET /static_pages/:id(.:format) static_pages#show
PUT /static_pages/:id(.:format) static_pages#update
DELETE /static_pages/:id(.:format) static_pages#destroy
users GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
root / posts#index
signin /signin(.:format) sessions#new
signup /signup(.:format) users#new
signout DELETE /signout(.:format) sessions#destroy
about /about(.:format) static_pages#about
projects /projects(.:format) static_pages#projects
Sessions Helper
module SessionsHelper
def sign_in(user)
cookies.permanent[:remember_token] = user.remember_token
self.current_user = user
end
def current_user=(user)
#current_user = user
end
def current_user
#current_user ||= User.find_by_remember_token(cookies[:remember_token])
end
def signed_in?
!current_user.nil?
end
def sign_out
self.current_user = nil
cookies.delete(:remember_token)
end
end
Based on your view markup, it looks like you should be looking for..
params[:email].downcase, instead of params[:session][:email].downcase.
The form tag isn't scoped to a session object so the params aren't matching correctly. Drop the session in the params code and you should be ok.

How to reroute standard rest actions to devise controller?

I have been building devise into a small Rails app. It's a pretty standard setup but one wrinkle is that the default authentication rules need to be changed for this project. Non-idempotent registration actions must all be restricted to only authenticated users.
To do this, I've written a custom registrations controller and linked it up in the routing. All the custom controller really has to do is alter the filtering requirements. Based on the Rails controller filtering documentation, I got this working with a minimum of effort.
But by itself that only applies to devise-specific actions like /users/sign_up or /users/edit. I would also like to wire in the standard Rails actions (/users/new, /users/1/edit, etc) to the custom controller. I can get the action to instantiate the controller -- leading the horse to water so to speak -- but when the action is new instead of sign_up, it crashes out during the filtering.
The problem appears to be that resource_name yields nil when the action is 'new', but is fine when it's 'sign_up'. I don't understand why devise cares or where the distinction is represented in code. I've looked at other questions like Update the User controller of devise and Override devise registrations controller and Custom Devise controller but they don't get into this issue.
The specific error I am getting is
NoMethodError in RegistrationsController#new
undefined method `name' for nil:NilClass
and the top of the trace is
devise (2.1.2) app/controllers/devise_controller.rb:22:in
resource_name' app/controllers/registrations_controller.rb:104:in
authenticate_scope!'
It is apparently happening the first time devise_mapping is referenced. But as per the above stackoverflow question I have also explicitly provided helpers for devise_mapping, and they don't even get called.
Can anyone explain or help me figure out where to look further?
from routes.rb:
Fs::Application.routes.draw do
devise_for :users, :controllers => { :registrations => 'registrations' }
resources :users, :except => [:index, :show], :controller => 'registrations'
resources :users, :only => [:index, :show]
[...]
rake routes reports:
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) registrations#cancel
user_registration POST /users(.:format) registrations#create
new_user_registration GET /users/sign_up(.:format) registrations#new
edit_user_registration GET /users/edit(.:format) registrations#edit
PUT /users(.:format) registrations#update
DELETE /users(.:format) registrations#destroy
users POST /users(.:format) registrations#create
new_user GET /users/new(.:format) registrations#new
edit_user GET /users/:id/edit(.:format) registrations#edit
user PUT /users/:id(.:format) registrations#update
DELETE /users/:id(.:format) registrations#destroy
GET /users(.:format) users#index
GET /users/:id(.:format) users#show
my registrations_controller.rb:
class RegistrationsController < Devise::RegistrationsController
prepend_before_filter :authenticate_scope!, :except => [:index, :show]
skip_filter :require_no_authentication
end
my users_helper.rb:
module UsersHelper
# used by devise
def resource_name
:user
end
def resource
#resource ||= User.new
end
def devise_mapping
#devise_mapping ||= Devise.mappings[:user]
end
end
using:
Rails 3.2.6
Ruby 1.9.3
devise 2.1.2
Update: pasted in the correct trace output.
So one solution appears to be to add
devise_scope :user do
get '/users/new' => 'registrations#new'
end
into routes.rb. This may not be the best answer but it works.

How do I remove the Devise route to sign up?

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