I got an Rails 3 app that uses Devise. I am just wondering how I can "kill" the current session?
This works but I do not know what it does
Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name)
This does not work
current_user = nil
This does not work either
session[:current_user] = nil
you can do like this
sign_out current_user
or
sign_out :user # sign_out(scope)
or
sign_out #user # sign_out(resource)
You probably want the sign_out method, and pass either the user or scope (eg :user) that you want to sign out.
Check out the Devise Ruby Doc for more information.
Related
I need to sign in fron non-devise controller. I found this link from devise wiki, but I get error :
wrong number of arguments (2 for 0)
I did exactly like in the link. What went wrong? Thanks
My code :
sign_in(:site, Site.find(params["si"]))
sign_in(:user, User.find(params[:id])
If you do a binding.pry after you'll see that current_user is set.
For some reason, doing a redirect after this will make current_user nil.
That's why I set something in the session like this and then redirect, and then check if that session id is set and then use it to do the above code:
session[:new_user_id] = params[:id]
you need to pass agruments post you code for clarity
sign_in(:user, User.find(params[:id]))
I'm probably late. But had the same problem and as it turns out I had a sign_in method in my users controller.
Did you check for a sign_in method in the controller where you are calling the sign_in method?
I have had this solution for Omniauth & Github implemented and working fine but sometime in the last few months it stopped working.
The error I'm getting when I try to login is: (422) The change you wanted was rejected.
Specifically in the Heroku logs I'm seeing:
ActiveRecord::RecordInvalid (Validation failed: Password can't be blank):
app/models/user.rb:18:in `create_from_omniauth'
app/models/user.rb:14:in `from_omniauth'
app/controllers/sessions_controller.rb:4:in `create'
Do I need to save the credentials when I create the user?
My user model:
def self.from_omniauth(auth)
where(auth.slice("provider", "uid")).first || create_from_omniauth(auth)
end
def self.create_from_omniauth(auth)
create! do |user|
user.provider = auth["provider"]
user.uid = auth["uid"]
user.name = auth["info"]["nickname"]
user.email = auth["info"]["email"]
user.image = auth["info"]["image"]
end
end
Sessions controller:
class SessionsController < ApplicationController
def create
user = User.from_omniauth(env["omniauth.auth"])
session[:user_id] = user.id
redirect_to root_url, notice: "Signed in!"
end
def destroy
session[:user_id] = nil
redirect_to root_url, notice: "Signed out!"
end
end
Facebook's omniauth error "the change you wanted was rejected"
might appear because of your validations set in the model. I had to refactor my validation for users having one unique email, which wasn't working when a user would try to facebook login with the same email.
Look at your logs. heroku logs -t
It looks like you're either validating presence of the password field in your User model or using has_secure_password, which does that under the covers.
If you're doing that validation yourself, you can just add a clause like :if => :password_changed? to the validation.
If you're using has_secure_password, it depends which version of Rails you're using. Any version with these two changes (I believe only Rails 4) support passing a validations: false option to has_secure_password. Otherwise, there's not really a good solution, other than maybe setting a random dummy password when you create the user then letting them change it immediately.
I had this issue when the time on my gitlab server was out of sync, i restarted ntpd, which corrected the time on the server and the problem was resolved
I'm new to rails and I installed devise for user authentication. It all started innocently enough when I encountered erros while trying to do stuff like...
div= current_user.username
So of course, my first inclination was to...
-if current_user
div= current_user.username
-else
div= "Guest"
The problem is that my templates are full of this conditional logic and I want to clean up my mess, but I'm not sure how. Should I create a new Guest user and assign it to current_user? (even then, I'm not sure how to do that).
What is a good approach to dealing with nil current_user in Rails?
Why not just put it in a helper?
def username
if current_user
div= current_user.username
else
div= "Guest"
end
end
I have currently set my app so that on successful sign in the app redirects the user to their profile at localhost:3000/users/id however if I am the first user id => 1 and type users/2 I have full access to this profile. I have been trying to find how to stop this using devise. I'm pretty new to rails so I'm sure I'm missing something simple, I have used the before_filter :authenticate_user! but this is obviously just checking if a user is signed in, but doesn't limit access to other users' profiles. I have read a bit on CanCan but this seems a bit overkill for what I am trying to achieve. Any pointers much appreciated.
users_controller.rb
class UsersController < ApplicationController
before_filter :authenticate_user!
before_filter :user_authorization
def index
#users = User.all
end
def show
#user = User.find(current_user[:id])
end
private
def user_authorization
redirect_to(root_url) unless current_user.id == params[:id]
end
end
This is being reported from the server:
Started GET "/users/2" for 127.0.0.1 at 2012-06-24 13:00:38 +0200
Processing by UsersController#show as HTML
Parameters: {"id"=>"2"}
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = 2 LIMIT 1
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 2]]
Redirected to http://localhost:3000/
Filter chain halted as :user_authorization rendered or redirected
Completed 302 Found in 20ms (ActiveRecord: 0.8ms)
In your controller:
class UsersController < ApplicationController
before_filter :validate_user, :only => :show
def show
#user = User.find(params[:id]
end
def validate_user
redirect_to courses_path unless current_user.id.to_s == params[:id]
end
end
Notice the current_user.id.to_s since current_user.id is an integer and params[:id] is a string.
In general, I'd say there are two approaches to solving this kind of problem:
Rolling your own code and implementing checks in your controllers (or potentially in your model classes), and
using a gem that enforces rules for you.
If you want to role-your-own, the simplest way would be to simply put checks in your controller that makes sure they get redirected if they try to look at a profile that isn't theirs. One way to do this using a before filter is this, though you'd want to adapt it for the behavior that makes sense for your app.
before_filter :validate_user
def validate_user
redirect_to home_path unless current_user and current_user.id == params[:id]
end
If you want to use a gem, then I'd recommend cancan as you've mentioned or another gem called Acts as Tenant. I've seen it used for similar things. But if all you want is to lock down the user profile, adding code to the controller probably works fine.
And voilĂ :
before_filter :user_authorization
private
def user_authorization
redirect_to(root_url) unless current_user.id == params[:id]
end
current_user is an helper that contains current logged user.
How can i override current_user of devise gem.
Actually I need to add web services for mobile-app.
Currently devise is managing session and 'current_user' for web-application.
Now Mobile app will send user_id to the server. I need to override current user like this
def current_user
if params[:user_id].blank?
current_user
else
User.find(params[:user_id])
end
end
Should I need to modify devise gem as plugin ? or something else ?
Kindly explain in detail as I am new in rails.
Kind regards,
According to the module Devise::Controllers::Helpers, current_user (together with all other devise helpers) is added to ApplicationController, which means that you can override it in this way:
# in application_controller.rb
def devise_current_user
#devise_current_user ||= warden.authenticate(scope: :user)
end
def current_user
if params[:user_id].blank?
devise_current_user
else
User.find(params[:user_id])
end
end
The other answer suggesting aliasing the method is actually not the best solution. Doug English's comment is the best solution:
# In ApplicationHelper
def devise_current_user
#devise_current_user ||= warden.authenticate(:scope => :user)
end
Here's the reason:
Suppose you're including your ApplicationHelper in your controller. If you need a method in your ApplicationHelper that relies on devise_current_user, given the alias solution inside the controller, you're out of luck.
But with the explicit method definition above, you can move the definition to the helper and call it from other methods and you still get to include it in the controller.
This is useful, for example, when you're developing a user impersonation solution and you need to show two different users in the view, one for the real admin (devise_current_user) and the other, the impersonated user (current_user).
Limbo-Peng's answer is great, but can be improved a little to make sure only admins can do this:
You'll need to also define a is_admin? method or is_admin attribute on the User class.
You may also want to use a different key than user_id, so it will never conflict with your regular parameters.
# to impersonate another user, e.g. for customer support
# only admins can do this..
#
alias_method :devise_current_user, :current_user
def current_user
if ! params[:user_id].blank? \
&& devise_current_user && devise_current_user.is_admin?
User.find(params[:user_id])
else
devise_current_user
end
end
Assuming we can trust our session data (which relies on whether you put user input in there without proper authorization or not), this might work as a Concern:
module Concerns
module ControllerWithImpersonation
extend ActiveSupport::Concern
included do
helper_method :devise_current_user
end
def current_user
if session[:impersonated_user_id].blank?
devise_current_user
else
User.find(session[:impersonated_user_id])
end
end
def devise_current_user
#devise_current_user ||= warden.authenticate(:scope => :user)
end
end
end
I'm using this in a project for now.
A minor question (in the answer, sorry) ... should I be aware of any changes in Devise or Warden that make devise_current_user above outdated?