I want to add OpenID authentication in my web. To do that I have follow several tutorials and used several plugins and gems and finally I manage to do something with devise_openid_authenticatable gem. I also have normal login/password authentication, Facebook authentication and Twitter authentication. Those three work perfectly.
Now I'm trying to override Devise's Session Controller , but when I do it, the normal login/password stops working. The error I get is:
ActiveRecord::RecordNotFound in Sessions#create
Couldn't find User without an ID
The rest of the authentication forms work OK, even the sign up works perfect. It's only the login/password authentication method...
I use Rails 3.0.1, Ruby 1.8.9 and Devise 1.4.9
routes.rb
MAWeb::Application.routes.draw do
[...]
devise_for :admins
devise_for :users, :controllers => {:registrations => 'registrations', :sessions => 'sessions'}
match '/users/openid' => 'users#openid_sign_in'
match 'openid/sign_in' => 'openid#sign_in', :as => :openid_sign_in
get 'openid/create'
match '/auth/:provider/callback' => 'authentications#create'
match '/auth/failure' => 'authentications#failure'
resources :subscription_contact_datas
resources :subscription_preferences do
collection do
post :create_with_params
end
member do
get 'delete_tag'
end
get 'fill_event_id', :on => :member
end
resources :event_states
resources :subscription_profiles do
collection do
put :update_profiles
end
end
resources :event_criteria_options
resources :subscriptions do
collection do
get :options_for_event_criteria
end
end
resources :event_criterias
resources :categories
resources :user_infos do
member do
get 'edit'
end
end
resources :events
resources :users do
member do
get 'showUserActivity'
end
end
resources :admins
resources :subscriptions_from_poi
root :to => "home#index"
namespace :user do
root :to => "users#index"
end
namespace :admin do
root :to => "admins#index"
end
*registrations controller's override works perfectly
EDIT: Added the most of the routes. The ones I omited are not important in my opinion.
Related
I have a platform built in Ruby on Rails that supports creation of websites with their own content, users etc. I want this route to show the sign in page for devise:
devise_scope :user do
get '/websites/:website_id/users/sign_in' => 'devise/sessions#new', :as => :website_session end
I get error:
No route matches {:action=>"show", :controller=>"websites", :locale=>:en, :id=>nil}
My resources are set up in the routes file as below. What should I change?
devise_for :users, :controllers => {:registrations => "devise/custom/registrations", :sessions => "devise/custom/sessions"}
resources :websites do
resources :users end
After a user signs in, I want them to be redirected to /users/2 or users/44, like a normal resource. (That way an admin can easily view any user's profile page just by knowing their id.)
I have no idea what is going on in my routes file. When a user logs in, I can see in the logs that it authenticates properly, and that my application_controller's after_sign_in_path_for is called.
But this is the error that I am getting when I try to redirect_to user_path(current_user).
No route matches {:action=>"show", :controller=>"users", :user_id=>11}
My config/routes.rb
devise_for :users, :path_names => {:sign_in => 'signin', :sign_out => 'signout', :sign_up => 'signup' }
devise_scope :user do
get "signin", :to => "devise/sessions#new"
get "signout", :to => "devise/sessions#destroy", via: :delete
get "signup", :to => "devise/registrations#new"
end
resources :users do
member do
get 'settings', to: 'users#edit'
end
end
My application_controller.rb
class ApplicationController < ActionController::Base
...
def after_sign_in_path_for(resource)
redirect_to user_path(:user_id=>current_user.id)
end
end
Shouldn't the resource :users block take care of creating a user show path? I do have a show method in my users_controller.rb. Please help, I've been trying to get this working for 2 days now.
My problem was that I was redirecting in the after_sign_in_path(resource) method instead of just returning the path:
def after_sign_in_path_for(resource)
return user_path(:user_id=>current_user.id)
end
is the correct way to do this.
I'm struggling with getting devise to redirect to a user's profile page after signin. My routes file looks like this:
get "profiles/index"
get "users/index"
get "users/show"
authenticated :user do
root :to => 'home#index'
end
root :to => "home#index"
devise_for :users
resources :users
scope ":username", :as => "user" do
match '/', :to => 'profiles#index'
end
I would like it to redirect to /myusername which the user's profile page. Thanks for your guys' help.
If you want to change the sign in redirect you can override the after_sign_in_path_for method by adding a new SessionsController as so:
class SessionsController < Devise::SessionsController
#after_sign_in_path_for is called by devise
def after_sign_in_path_for(user)
"/users/#{user.username}" #adjust the returned path as needed
end
end
As Ashikata mentioned you need to change the devise routing to the following if you're changing the session controller.
devise_for :users, :controllers => { :sessions => 'sessions' }
Alternatively, adding that modified after_sign_in_path_for method to your application controller should do the trick.
I'm working on a Rails-based API. I recently started attempting to version it. (I'm using the Versionist gem, in case it matters) One version ('v2') uses Devise and Omniauth to authenticate users through Facebook/Twitter.
I want all the routes associated with this version to have the appropriate version prefix (so users/:username/foo becomes v2/users/:username/foo, etc.), but I've already found out that putting devise_for inside the api_version block prevents the Devise helpers (current_user, user_signed_in?, etc.) from working, so it continues to live outside the block:
routes.rb:
devise_for :user, :path => '', :controllers => {:omniauth_callbacks => 'users/omniauth_callbacks'}, :skip => [:registrations, :confirmations, :sessions, :passwords]
api_version(:module => "V2", :path=>"v2") do
resources :authentications, :only => [:update, :destroy]
devise_scope :user do
post 'login' => 'sessions#create', :as => 'user_session'
get 'logout' => 'sessions#destroy'
post 'password' => 'devise/passwords#create'
put 'password' => 'devise/passwords#update'
end
end
Everything seemed great... except the Devise-generated omniauth routes:
rake routes output:
user_omniauth_authorize /auth/:provider(.:format)
user_omniauth_callback /auth/:action/callback(.:format)
Now, some google-fu revealed that there's a devise configuration setting for this, so I added the following to our devise initializer (config/initializers/devise.rb):
Devise.setup do |config|
config.omniauth_path_prefix = 'v2/auth'
end
Now, rake routes produces paths that look sensible:
user_omniauth_authorize /v2/auth/:provider(.:format) v2/users/omniauth_callbacks#passthru {:provider=>/(?!)/}
user_omniauth_callback /v2/auth/:action/callback(.:format) v2/users/omniauth_callbacks#(?-mix:(?!))
However, when I attempt to access this route by calling api.localhost/v2/auth/facebook, I get a routing error:
ActionController::RoutingError (No route matches [GET] "/v2/auth/facebook")
Any idea what's going on here?
You are missing the provider name in the routes so they don't match the facebook part in /v2/auth/facebook. The correct route destination should look something like v2/users/omniauth_callbacks#(?-mix:facebook).
Have you specified the provider in the user model?
devise_for ..., :omniauthable, :omniauth_providers => [:facebook]
For the record, I'm using Rails 3.2 and Devise 3.0 and the altered route seems to work (I haven't gone further yet to see if something else will break).
Consider this as a challenge rather than its general approach. The reason I mention this is because, it is generally preferred to incorporate admin-accessible features into the public facing site. This is what's required:
Devise model for Users, visitors accessing the public facing site
Devise model for Admins
Namespace or scope the admin 'area' to /admin. Admins can only login from this route.
Users can sign up directly from the site's public facing landing page; they are not forced to visit /users/sign_up as per the default devise generated route.
Consider overriding the default devise controllers
Thanks,
Mike.
The following seems like I've made some progress in the right direction; this at least provides identical out-of-the-box devise functionality for both users and admins, with the custom routing,
match 'admin', :controller => 'admin'
namespace :admin do
# to be updated later...
end
devise_for :users
#devise_for :admins, :path => "admin" # this works but uses the default
# Devise::SessionController
devise_for :admins,
:controllers => {
:sessions => "admin/sessions",
:passwords => "admin/passwords",
:registrations => "admin/registrations" }, :path => "admin",
:skip => [:sessions, :passwords, :registrations] do
get 'admin/sign_in' => 'admin/sessions#new', :as => :new_admin_session
post 'admin/sign_in' => 'admin/sessions#create', :as => :admin_session
get 'admin/sign_out' => 'admin/sessions#destroy', :as => :destroy_admin_session
get 'admin/sign_up' => 'admin/registrations#new', :as => :new_admin_registration
get 'admin/account' => 'admin/registrations#edit', :as => :edit_admin_registration
post 'admin/account' => 'admin/registrations#create', :as => :admin_registration
get 'admin/cancel' => 'admin/registrations#cancel', :as => :cancel_admin_registration
put 'admin/account' => 'admin/registrations#update'
delete 'admin/account' => 'admin/registrations#destroy'
post 'admin/password' => 'admin/passwords#create', :as => :admin_password
get 'admin/password/new' => 'admin/passwords#new', :as => :new_admin_password
get 'admin/password/edit' => 'admin/passwords#edit', :as => :edit_admin_password
put 'admin/password' => 'admin/passwords#update'
end
Ideas?
caveat: in this example, I've included the :registerable devise module in the Admin model just for testing during development. The sign_up route will, ultimately, be removed.
Much searching yielded (mind the pun) the following blog post that seems to indicate overriding a devise controller requires the re-mapping of all its specified 'HTTP verbs' as it were; this makes sense as unmapped ones would be handled by the default devise controller.
If anyone has more experience working with multiple devise models and the separated admin approach, I would be very much interested in your thoughts and suggestions!