I wanted to remove the devise routes, as I built custom routes and controllers for my purpose. However, I noticed that when I delete my devise_for :users line in routes and replace it with only...
Routes file
devise_scope :user do
delete 'logout', to: 'devise/sessions#destroy'
end
I am not getting an error:
View:
<% if user_signed_in? %>
Error:
"undefined method `user_signed_in?' for #<#Class:0x00007f984411aab0:0x00007f98441266f8>"
Why would a helper need routes? Which routes are required for it? Can I define only the helpers?
I also plan to use current_user.present? and sign_in #user, but do not know if they will error later, as I can not get passed the undefined Method.
From the Devise Gem: https://github.com/heartcombo/devise/blob/45b831c4ea5a35914037bd27fe88b76d7b3683a4/lib/devise/rails/routes.rb
# Let's say you have an User model configured to use authenticatable,
# confirmable and recoverable modules. After creating this inside your routes:
#
# devise_for :users
#
# This method is going to look inside your User model and create the
# needed routes:
#
# # Session routes for Authenticatable (default)
# new_user_session GET /users/sign_in {controller:"devise/sessions", action:"new"}
# user_session POST /users/sign_in {controller:"devise/sessions", action:"create"}
# destroy_user_session DELETE /users/sign_out {controller:"devise/sessions", action:"destroy"}
#
# # Password routes for Recoverable, if User model has :recoverable configured
# new_user_password GET /users/password/new(.:format) {controller:"devise/passwords", action:"new"}
# edit_user_password GET /users/password/edit(.:format) {controller:"devise/passwords", action:"edit"}
# user_password PUT /users/password(.:format) {controller:"devise/passwords", action:"update"}
# POST /users/password(.:format) {controller:"devise/passwords", action:"create"}
#
# # Confirmation routes for Confirmable, if User model has :confirmable configured
# new_user_confirmation GET /users/confirmation/new(.:format) {controller:"devise/confirmations", action:"new"}
# user_confirmation GET /users/confirmation(.:format) {controller:"devise/confirmations", action:"show"}
# POST /users/confirmation(.:format) {controller:"devise/confirmations", action:"create"}
devise_for is how Devise hooks into the entire framework and sets up its helpers. So skipping entirely is just not how you want to go about it. If you just want to change the name of the paths use the correct option instead:
# availabe path_names are
# :sign_in, :sign_out, :sign_up, :password, :confirmation, :unlock.
devise_for :users, only: :sessions,
path_names: {
sign_out: 'logout'
}
The skip: and only: options can be used to limit the generated routes:
devise_for :users,
only: :sessions,
path_names: {
sign_out: 'logout'
}
devise_for :users,
skip: [:registrations, :passwords, :confirmations],
path_names: {
sign_out: 'logout'
}
If you really want to use the path /user/... instead of /users/...:
devise_for :users, only: :sessions,
path: 'user',
path_names: {
sign_out: 'logout'
}
Not really something I would recommend though.
See ActionDispatch::Routing::Mapper#devise_for.
Related
I have created an Admin model with the Devise gem. Using the Devise controller generator, I now have a app/controllers/admins folder containing all the stock controllers for me to modify if I choose, such as sessions_controller, passwords_controller, etc.
However, I can't figure out how to just get an Admin controller and simple admin routes like admin_path or new_admin_path.
Here's my rake routes | grep admin
new_admin_session GET /admin/sign_in(.:format) admins/sessions#new
admin_session POST /admin/sign_in(.:format) admins/sessions#create
destroy_admin_session DELETE /admin/sign_out(.:format) admins/sessions#destroy
new_admin_password GET /admin/password/new(.:format) devise/passwords#new
edit_admin_password GET /admin/password/edit(.:format) devise/passwords#edit
admin_password PATCH /admin/password(.:format) devise/passwords#update
PUT /admin/password(.:format) devise/passwords#update
POST /admin/password(.:format) devise/passwords#create
admin_root GET /admin(.:format) admins/sessions#portal
admin_sign_out GET /admin/sign_out(.:format) admin/sessions#destroy
And here are the relevant parts of my routes.rb
devise_for :admins, path: 'admin', controllers: { sessions: 'admins/sessions' }
devise_scope :admin do
get "/admin", to: 'admins/sessions#portal', as: 'admin_root'
get "/admin/sign_out", to: 'admin/sessions#destroy', as: 'admin_sign_out'
end
You'll see that I've currently got a portal method in my Admin::SessionsController, which is my current workaround. I know the right place for that page is in an AdminsController but I can't figure out how to set that up.
Adding admins: 'admins/admins' to the devise_for :admins, controllers: block doesn't give me any new routes. I tried adding an AdminsController with methods but that doesn't help either, trying to go to /admin/new or /admins/new says no route matches.
This is how I have my device and namespaces set up
# config/routes.rb
Rails.application.routes.draw do
devise_for :admins, :controllers => { registrations: 'admins/registrations',
sessions: 'admins/sessions',
passwords: 'admins/passwords',
confirmations: 'admins/confirmations'
}
authenticate :admin do
namespace :admins do
...
root 'dashboards#index'
end
end
...
root 'pages#index'
Now controllers are also important.
#app/controllers/admin_controller.rb
class AdminController < ApplicationController
layout 'admins/application'
before_filter :authenticate_admin!
end
The Devise controllers I have them set like this
#app/controllers/admins/sessions_controller.rb
class Admins::SessionsController < Devise::SessionsController
layout 'admins/application'
...
end
Repeat this process for all your other device controllers
Let me know if this helps you out
I added user profile to Devise from some tutorials I found online and linking to profile works great. However now I'm having problem with user signup.
I assume, since I have created users_controller.rb for user profile, it is looking into users_controller.rb now for all actions. So, regarding the sign up, I added create def, then it asked def new, then def update and so on... Things got really complicated and I got different type of errors!
MY QUESTION:
Is it possible to redirect all actions to the default Devise signup, login, update, ... while I keep user_controllers.rb only for user profile?
Thank you!
route
Rails.application.routes.draw do
resources :users
devise_for :users
devise_scope :user do
get 'register', to: 'devise/registrations#new', as: :register
get 'login', to: 'devise/sessions#new', as: :login
get 'logout', to: 'devise/sessions#destroy', as: :logout
end
root 'posts#index'
end
Controller
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
end
end
Routing and Controllers in Devise
Your config/routes.rb determines the actions triggered with each GET/POST/PUT/PATCH request made to urls
You can read more about this at the following link
Routing/Controller in Devise
When you configure Devise you set the routes by using the devise_for method in your routes.rb
# config/routes.rb
Rails.application.routes.draw do
devise_for :users
end
to read more about the method devise_for read the documentation
devise_for will generate the following routes:
# Session routes for Authenticatable (default)
new_user_session GET /users/sign_in {controller:"devise/sessions", action:"new"}
user_session POST /users/sign_in {controller:"devise/sessions", action:"create"}
destroy_user_session DELETE /users/sign_out {controller:"devise/sessions", action:"destroy"}
# Password routes for Recoverable, if User model has :recoverable configured
new_user_password GET /users/password/new(.:format) {controller:"devise/passwords", action:"new"}
edit_user_password GET /users/password/edit(.:format) {controller:"devise/passwords", action:"edit"}
user_password PUT /users/password(.:format) {controller:"devise/passwords", action:"update"}
POST /users/password(.:format) {controller:"devise/passwords", action:"create"}
# Confirmation routes for Confirmable, if User model has :confirmable configured
new_user_confirmation GET /users/confirmation/new(.:format) {controller:"devise/confirmations", action:"new"}
user_confirmation GET /users/confirmation(.:format) {controller:"devise/confirmations", action:"show"}
POST /users/confirmation(.:format) {controller:"devise/confirmations", action:"create"}
If the client/browser performs a GET request to the server via the url /users/sign_in, the server will execute the action new from the controller in the folder app/controllers/devise/sessions
That is where my views are generated and even if I do not have the devise controller, this is how it is mapped.
You can override this behavior, as explained in this guide, bu using the following syntax:
devise_for :users, controllers: { sessions: 'users/sessions' }
This means that for sessions you are going to use the controller located in the folder app/controllers/users/sessions and not devise/sessions.
You can test this, generate your routes and see how you will have the routes for every action.
The Best Practice
The best practice as suggested from Devise is just generating the devise controller, which will have actions that are already wired with the Devise routing. Each action from the controller will call with super the Devise controller actions, if you want to enhance or change that logic you can do it by reading the Devise API
To that controller you can add any action you want then configure appropriately your routing
For routing and controller info from ruby on rails guide
http://guides.rubyonrails.org/action_controller_overview.html
http://guides.rubyonrails.org/routing.html
Hi im doing a kind of blog to learn Rails, using the Getting started tutorials like these
http://guides.rubyonrails.org/getting_started.html
http://guides.rubyonrails.org/routing.html
I have manage to do the posts sections and i also do a admin/posts section, this is the problem now..
Ths system is "conflicting" and admin goes to domain.com/posts instead of admin/posts.
I think the problem is the way i build the links..
In the tutorial to link a item yo do
<h2><%= link_to post.title, post %></h2>
I have tried
<h2><%= link_to post.title, admin_post_path %></h2>
And similars but i get
undefined local variable or method `admin_post_path' for #<#<Class:0x007fe3e990ef28>:0x007fe3e6e3b508>
How does this works i mean i have done rake routes and i see there the routes, but i cant use them
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 GET /admin/users(.:format) admin/users#index
POST /admin/users(.:format) admin/users#create
new_user GET /admin/users/new(.:format) admin/users#new
edit_user GET /admin/users/:id/edit(.:format) admin/users#edit
user GET /admin/users/:id(.:format) admin/users#show
PUT /admin/users/:id(.:format) admin/users#update
DELETE /admin/users/:id(.:format) admin/users#destroy
posts GET /admin/posts(.:format) admin/posts#index
POST /admin/posts(.:format) admin/posts#create
new_post GET /admin/posts/new(.:format) admin/posts#new
edit_post GET /admin/posts/:id/edit(.:format) admin/posts#edit
post GET /admin/posts/:id(.:format) admin/posts#show
PUT /admin/posts/:id(.:format) admin/posts#update
DELETE /admin/posts/:id(.:format) admin/posts#destroy
players GET /players(.:format) players#index
POST /players(.:format) players#create
new_player GET /players/new(.:format) players#new
edit_player GET /players/:id/edit(.:format) players#edit
player GET /players/:id(.:format) players#show
PUT /players/:id(.:format) players#update
DELETE /players/:id(.:format) players#destroy
player_steps GET /player_steps(.:format) player_steps#index
POST /player_steps(.:format) player_steps#create
new_player_step GET /player_steps/new(.:format) player_steps#new
edit_player_step GET /player_steps/:id/edit(.:format) player_steps#edit
player_step GET /player_steps/:id(.:format) player_steps#show
PUT /player_steps/:id(.:format) player_steps#update
DELETE /player_steps/:id(.:format) player_steps#destroy
coach_steps GET /coach_steps(.:format) coach_steps#index
POST /coach_steps(.:format) coach_steps#create
new_coach_step GET /coach_steps/new(.:format) coach_steps#new
edit_coach_step GET /coach_steps/:id/edit(.:format) coach_steps#edit
coach_step GET /coach_steps/:id(.:format) coach_steps#show
PUT /coach_steps/:id(.:format) coach_steps#update
DELETE /coach_steps/:id(.:format) coach_steps#destroy
candidates GET /candidates(.:format) candidates#index
POST /candidates(.:format) candidates#create
new_candidate GET /candidates/new(.:format) candidates#new
edit_candidate GET /candidates/:id/edit(.:format) candidates#edit
candidate GET /candidates/:id(.:format) candidates#show
PUT /candidates/:id(.:format) candidates#update
DELETE /candidates/:id(.:format) candidates#destroy
payment_notifications GET /payment_notifications(.:format) payment_notifications#show
post GET /posts/:id(.:format) posts#show
posts GET /posts(.:format) posts#index
admin_posts_path GET /admin/posts(.:format) admin/posts#index
admin_posts_path POST /admin/posts(.:format) admin/posts#index
admin_post_path GET /admin/posts/:id(.:format) admin/posts#show
new_admin_post_path GET /admin/posts/new(.:format) admin/posts#new
/*a(.:format) errors#routing
choose GET /user_type(.:format) home#user_type
root / devise/sessions#new
Also tried this
<h2><%= link_to post.title, url_for([#post]) %></h2>
this throw:::: Nil location provided. Can't build URI.
=( any documentation on doing this, ?? do you know where i can find it
Routes.rb
Consult::Application.routes.draw do
devise_for :users, :controllers => { :registrations => "registrations" }
scope "/admin" do
resources :users, :controller => 'admin/users'
resources :posts, :controller => 'admin/posts'
end
resources :players
resources :player_steps
resources :coach_steps
resources :candidates
resource :payment_notifications, :only => :show
#match 'candidates' => 'candidates#index'
#resources :posts
get '/posts/:id', to: 'posts#show', as: 'post'
get '/posts/', to: 'posts#index', as: 'posts'
get '/admin/posts/', to: 'admin/posts#index', as: 'admin_posts_path'
post '/admin/posts/', to: 'admin/posts#index', as: 'admin_posts_path'
get '/admin/posts/:id', to: 'admin/posts#show', as: 'admin_post_path'
get '/admin/posts/new', to: 'admin/posts#new', as: 'new_admin_post_path'
match '*a', :to => 'errors#routing'
# The priority is based upon order of creation:
# first created -> highest priority.
# Sample of regular route:
# match 'products/:id' => 'catalog#view'
# Keep in mind you can assign values other than :controller and :action
# Sample of named route:
# match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase
# This route can be invoked with purchase_url(:id => product.id)
# Sample resource route (maps HTTP verbs to controller actions automatically):
# resources :products
# Sample resource route with options:
# resources :products do
# member do
# get 'short'
# post 'toggle'
# end
#
# collection do
# get 'sold'
# end
# end
# Sample resource route with sub-resources:
# resources :products do
# resources :comments, :sales
# resource :seller
# end
# Sample resource route with more complex sub-resources
# resources :products do
# resources :comments
# resources :sales do
# get 'recent', :on => :collection
# end
# end
# Sample resource route within a namespace:
# namespace :admin do
# # Directs /admin/products/* to Admin::ProductsController
# # (app/controllers/admin/products_controller.rb)
# resources :products
# end
# You can have the root of your site routed with "root"
# just remember to delete public/index.html.
#root :to => "devise/sessions#new"
get 'user_type', to: 'home#user_type', as: :choose
devise_scope :user do
root :to => "devise/sessions#new"
end
# See how all your routes lay out with "rake routes"
# This is a legacy wild controller route that's not recommended for RESTful applications.
# Note: This route will make all actions in every controller accessible via GET requests.
# match ':controller(/:action(/:id))(.:format)'
end
Try using namespace, as opposed to the scope, as the namespace is much better for nesting. your routes file should look something like this.
namespace :admin do
resources :users
resources :posts
end
resources :players
resources :player_steps
resources :coach_steps
resources :candidates
resource :payment_notifications, :only => :show
#match 'candidates' => 'candidates#index'
resources :posts
you can remove
get '/posts/:id', to: 'posts#show', as: 'post'
get '/posts/', to: 'posts#index', as: 'posts'
get '/admin/posts/', to: 'admin/posts#index', as: 'admin_posts_path'
post '/admin/posts/', to: 'admin/posts#index', as: 'admin_posts_path'
get '/admin/posts/:id', to: 'admin/posts#show', as: 'admin_post_path'
get '/admin/posts/new', to: 'admin/posts#new', as: 'new_admin_post_path'
as the namespace and the resources handle their generation
full routes file should be
Consult::Application.routes.draw do
devise_for :users, :controllers => { :registrations => "registrations" }
namespace :admin do
resources :users
resources :posts
end
resources :players
resources :player_steps
resources :coach_steps
resources :candidates
resources :posts
resource :payment_notifications, :only => :show
get 'user_type', to: 'home#user_type', as: :choose
devise_scope :user do
root :to => "devise/sessions#new"
end
end
I'm really missing something here.
I have read many things about devise redirects (seems like it is hard to implement for most people ...) but in my case I really don't get it.
Sometimes I read that the methods after_<action>_path_for(resource) should be in the ApplicationController, sometimes it is mentionned to be in a specific controller, overriding the devise one.
I'd rather have them in my ApplicationController since it bothers me to create more Controllers just for a redirect, but if it is not possible at the end, I won't insist...
Here's the deal:
I have in my ApplicationController : (and some others, but that's enough for the example)
def after_update_path_for(user)
flash[:notice] = 'Successfully updated password'
edit_user_path(user)
end
def after_inactive_sign_up_path_for(user)
flash[:notice] = 'Welcome! Please follow the steps!'
me_new_path
end
def after_sign_up_path_for(user)
flash[:notice] = 'Welcome! Please follow the steps!'
me_new_path
end
def after_sign_in_path_for(user)
if user.sign_in_count == 1
me_new_path
else
root_path
end
end
And the crazy thing, is that after_sign_in_path_for is called, but not the other ones. Like when the user signs up it's the if user.sign_in_count == 1 that redirects him, not the after_inactive_sign_up_path_for nor the after_sign_up_path_for
How come?
It could be related to my routes, so here's my routes.rb extract:
devise_for :user, :skip => [:sessions, :registrations], :path => ''
devise_scope :user do
get :register, :to => 'devise/registrations#new'
post :register, :to => 'devise/registrations#create'
put :update_password, :to => 'devise/my_registrations#update'
get :login, :to => 'devise/sessions#new'
get :login, :to => 'devise/sessions#new', :as => :new_copasser_session
post :login, :to => 'devise/sessions#create'
delete :logout, :to => 'devise/sessions#destroy'
end
And I'm using Devise 3.1.0 with Ruby 1.9.3 and Rails 3.2.13
Thanks for the help!
EDIT
Thanks #rich-peck for your answer. I updated my routes.rb this way :
devise_for :users, :path => '', :path_names => {
:sign_in => :login,
:registration => :register,
:sign_up => '',
:sign_out => :logout
}
which gives me the same routes as the previous ones (except I can't use login_path helper anymore but it's not a big deal), but I still get the same results concerning redirects.
Here is the result of rake routes:
new_user_session GET /login(.:format) devise/sessions#new
user_session POST /login(.:format) devise/sessions#create
destroy_user_session DELETE /logout(.:format) devise/sessions#destroy
user_password POST /password(.:format) devise/passwords#create
new_user_password GET /password/new(.:format) devise/passwords#new
edit_user_password GET /password/edit(.:format) devise/passwords#edit
PUT /password(.:format) devise/passwords#update
cancel_user_registration GET /register/cancel(.:format) devise/registrations#cancel
user_registration POST /register(.:format) devise/registrations#create
new_user_registration GET /register(.:format) devise/registrations#new
edit_user_registration GET /register/edit(.:format) devise/registrations#edit
PUT /register(.:format) devise/registrations#update
DELETE /register(.:format) devise/registrations#destroy
user_confirmation POST /confirmation(.:format) devise/confirmations#create
new_user_confirmation GET /confirmation/new(.:format) devise/confirmations#new
GET /confirmation(.:format) devise/confirmations#show
Any idea?
Devise relies heavily on a central variable called "resource". This variable defines how devise operates on your system, and is why you have to "attach" Devise to :users or similar
People get problems with Devise because they don't follow the conventions, and put their forms everywhere. If they read the Devise readme, they'd appreciate that it's quite flexible :)
I believe your problem is to do with your routes, in that you might want to consolidate all those static routes into something like this:
devise_for :users, :path => '', :controllers => {:sessions => 'sessions', :registrations => 'registrations'}, :path_names => { :sign_in => 'login', :password => 'forgot', :confirmation => 'confirm', :unlock => 'unblock', :registration => 'register', :sign_up => 'new', :sign_out => 'logout'}
So thanks to #rich-peck's help, we figured it out.
The question was why do after_sign_in_path_for behave differently than after_sign_up_path_for and cie ?
It appears, in the devise sources, that after_sign_in_path_for is defined in a helper, whereas the other ones are methods of their controller (eg. Devise::RegistrationsController < DeviseController)
Hence for after_sign_in_path_for it works overriding in the ApplicationController, whereas for the other ones, it is necessary to create a registrations_controller.rb file, to override the method in it:
class RegistrationsController < Devise::RegistrationsController
protected
def after_sign_up_path_for(copasser)
flash[:notice] = 'Welcome! Please follow the steps!'
me_new_path
end
end
and to set the router.rb this way:
devise_for :copassers, :controllers => {
:registrations => :registrations
}
I suppose the behaviour is different because :registerable, :recoverable etc. are modules of devise, not necessarily used, and the helper wouldn't be appropriate in that case. A devise contributor could help us on this point.
I'm trying to setup Devise 3.1.0 with Rails 4.0.0.
I have configured my router like so:
devise_for :users,
:controllers => {
:registrations => 'users/registrations',
:sessions => 'users/sessions'
},
:path_names => {
:sign_in => 'login',
:sign_out => 'logout',
:sign_up => 'new'
}
new_user_session GET /users/login(.:format) users/sessions#new
user_session POST /users/login(.:format) users/sessions#create
destroy_user_session DELETE /users/logout(.:format) users/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) users/registrations#cancel
user_registration POST /users(.:format) users/registrations#create
new_user_registration GET /users/new(.:format) users/registrations#new
edit_user_registration GET /users/edit(.:format) users/registrations#edit
PATCH /users(.:format) users/registrations#update
PUT /users(.:format) users/registrations#update
DELETE /users(.:format) users/registrations#destroy
I've also turned on scoped views, and overridden the default views and registration controller:
# config/initializers/devise.rb
config.scoped_views = true
rails generate devise:views users
# app/controllers/users/registrations_controller.rb
#
# NOTE: I created this class, so creating new users could only be done by authenticated users.
#
class Users::RegistrationsController < Devise::RegistrationsController
before_filter :authenticate_user!
prepend_before_filter :authenticate_scope!
skip_before_filter :require_no_authentication
end
# app/controllers/users/sessions_controller.rb
# (currently empty)
class Users::SessionsController < Devise::SessionsController
end
The problem:
Why devise is ignoring the :path_names settings above in some situations?
For example, this method will not use the :sign_in setting above, and returns an incorrect path:
new_session_path(resource_name)
=> /users/sign_in
resource_name
=> user
Whereas this method returns the correct path:
new_user_session_path
=> /users/login
The problem is, Devise internally uses the former method, and keeps redirecting to the wrong path when the user is not signed in.
Have I mis-configured something, or is Devise not working correctly? Could this be a Rails 4 issue?
I'm not sure what the issue I was having was. (I'd still be interested to know, if anyone knows).
But I've found another way to express what I wanted with devise, and it seems to work OK:
devise_for :users,
:controllers => {
:registrations => 'users/registrations'
},
:path_names => {
:sign_up => 'new'
}, :skip => [:sessions]
as :user do
get '/users/login' => 'devise/sessions#new', :as => :new_user_session
post '/users/login' => 'devise/sessions#create', :as => :user_session
match '/users/logout' => 'devise/sessions#destroy', :as => :destroy_user_session,
:via => Devise.mappings[:user].sign_out_via
end
I think you trying to solve your question with the wrong feature, in this link show you how to write another routes for devise, in my app I've recreated the routes with this:
devise_scope :user do
get '/cadastrar' => 'devise/registrations#new'
get '/entrar' => 'devise/sessions#new'
get '/editar' => 'devise/registrations#edit'
delete '/sair' => 'devise/sessions#destroy'
end
I'm glad if work!