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.
Related
I am using devise_invitable gem in my application.
If a user is already signed in the application and he clicks on the Accept Invitation link then he is redirected to devise after_sign_in_path_for.
I want to change that and give the user some flash that he is signed in the application and needs to sign out before continuing.
After clicking on Accept Invitation link my control goes to Users::InvitationsController#edit. But I am not able to get current_user in Invitations Controller.
My routes and action is as:
devise_for :users, controllers: { registrations: "registrations", :invitations => 'users/invitations', sessions: "sessions", confirmations: "confirmations", passwords: "passwords" }
def edit
Rails.logger.debug current_user.inspect
if current_user.present?
Rails.logger.debug "---current user---"
else
render :edit
end
end
Can some one please suggest how I can get the current user in invitations controller.
This is the line in InvitationsController that prevents current_user from being assigned:
prepend_before_filter :require_no_authentication, :only => [:edit, :update, :destroy]
Add this to your controller and current_user will be assigned:
skip_filter :require_no_authentication, :only => :edit
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.
I've followed the Devise wiki to switch the login route from /users/sign_in to /login. My routes file looks like this:
devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" }
devise_scope :user do
get '/login' , :to => 'devise/sessions#new' , :as => :login
delete '/logout', :to => 'devise/sessions#destroy', :as => :logout
end
and my user model has this
class User < ActiveRecord::Base
devise :omniauthable, :database_authenticatable
end
I have a common scenario where a user is logged out, tries to access a restricted page, and then redirected to log himself in.
However, when that user is redirected, devise sends them to /users/sign_in path instead of /login.
The only way I could make the redirection to the /login url work is by adding this to the top of my routes.rb:
match "/users/sign_in" => redirect('/login')
which adds a redirect to my application, which in turn messes up tests - whenever I do something like this:
current_url.should == login_path
I get an error saying the expected path was "/login" and the actual was "/users/sign_in".
Did I miss something here - what's an elegant way to work around it? thanks.
side note
I only use :omniauthable to authenticate, but I added :database_authenticatable to devise configuration to force it to go to a dedicated login page.
Otherwise, devise always directs to the root path, so it would seem. If you know of a better way to do that, please - chime in.
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 have a set of API routes in rails as follows
namespace "api" do
namespace "v1" do
resources :users do
resources :posts
resources :likes
...
end
end
end
So far, so good. I can GET /api/v1/users/fred_flintstone and retrieve all of the information for that user.
What I would like to do now is add the concept of "me" (ala facebook) such that if the user is authenticated (fred_flintstone), I can also do the following
GET /api/v1/me
GET /api/v1/me/posts
...
I require both sets of routes. So I want to achieve the same results either using GET /api/v1/me/posts OR GET /api/v1/users/fred_flintstone/posts.
I've been through the route tutorial and have googled so a pointer would be as much appreciated as a direct answer.
EDIT:
What I've done that has worked is pretty hacky. I've created a second set of entries in the routes table using a scope:
scope "/api/v1/me", :defaults => {:format => 'json'}, :as => 'me' do
resources :posts, :controller => 'api/v1/users/posts'
resources :likes, :controller => 'api/v1/users/likes'
...
end
And then I added a set_user method that tests for the presence of params[:user_id]. I'm really looking for a way to DRY this up.
What about leaving the routes the way they are in your post, and just solving this inside the controller?
Heres a before_filter that you could apply to all of the routes you have which pull a User from a :user_id.
# Set the #user variable from the current url;
# Either by looking up params[:user_id] or
# by assigning current_user if params[:user_id] = 'me'
def user_from_user_id
if params[:user_id] == 'me' && current_user
#user = current_user
else
#user = User.find_by_user_id params[:user_id]
end
raise ActiveRecord::RecordNotFound unless #user
end
Then in your controller functions you can just use the #user variable without having to worry about whether the user passed a user_id, or me.
Hope that helps! :)
EDIT:
Lemme take another shot, given your comments.
How about a function that lists all the resources you wish to access via both the standard routes and the /me route. Then you can just use the function in both the namespaces you require.
routes.rb
# Resources for users, and for "/me/resource"
def user_resources
resources :posts
resources :likes
...
end
namespace 'api' do
namespace 'v1' do
resources :users do
user_resources
end
end
end
scope '/api/v1/:user_id', :constraints => { :user_id => 'me' },
:defaults => {:format => 'json'}, :as => 'me' do
user_resources
end
# We're still missing the plain "/me" route, for getting
# and updating, so hand code those in
match '/api/v1/:id' => 'users#show', :via => :get,
:constraints => { :id => 'me' }
match '/api/v1/:id' => 'users#update', :via => :put,
:constraints => { :id => 'me' }