Rails -> Devise -> how to access current_user from Module - ruby-on-rails

I'm currently using Rails 3.2.9 with devise 3.0.4
I can access Devise current_user in Controller without any problem.
However, when I'm trying to access current_user in Module as below and receive error.
c_time = DateTime.current.in_time_zone(current_user.local_timezone)
NameError (undefined local variable or method `current_user' for DateCalculator:Module):
It would be great if someone please advise what's the best way to access current_user from Module.
Many Thanks in advance.

Try this one instead of using current_user object
UserSession.find.user

If your module does something specific to current signed in user, your can follow this way
config/initializers/user_specific_time.rb
module Devise
module Controllers
module Helpers
def user_specific_time
c_time = DateTime.current.in_time_zone(current_user.local_timezone)
end
end
end
end

There is a Gem called sentient_user it is a cheeky approach but it does exactly what you need ;) which is to have access to current logged in user, from view | Controller | Model etc
https://rubygems.org/gems/sentient_user

Related

Call helper function from rails 4 notifications subscribe

I need to save all controller notification to database. I create a /config/initializers/notifications.rb
ActiveSupport::Notifications.subscribe('process_action.action_controller') do |name, start, finish, id, payload|
Action.create(
action_type: name,
user: current_user,
data: payload
)
end
but I get error:
undefined local variable or method `current_user' for main:Object
current_user is a helper it app/helpers/session_helper.rb and it works in entire application.
I need to know user, which made action. How can I call current_user in this context?
current_user is usually set in the application_controller of your
application. If you use a gem like Devise to handle user
authentications for example, they take care of setting such method for
you.
The initializers' code is executed when you launch your application on
your server (local machine or remote server), therefor you understand
that a "current_user" (understand a "logged in" user) simply does not
exists (yet).
Source - is it possible for current_user to be initializer, in rails 3?
Hope this helps!
current_user is a helper it app/helpers/session_helper.rb and it works in entire application.
Let me correct you here.
You can't access current_user in your initializer files. Initializers are run once on application startup, so don't expect accessing current_user like this.
I found solution: append_info_to_payload
class ApplicationController < ActionController::Base
...
def append_info_to_payload(payload)
super
payload[:current_user] = current_user
end
From this answer:
How to add attribute to existing Notifications payload?

How can I sign out a devise user from the Rails console?

My devise users are "database_authenticatable" and "token_authenticatable". I've tried deleting the "authentication_token" field in the database for that user from the console, but they still seem to be able to use their existing auth token. Deleting the user entirely works, but I don't want to go that far.
Edit: for clarity. I want to use the rails console to sign out a user. i.e. run rails console and then some command.
Devise provides helper methods to do these things:
user = User.find(params[:id])
sign_in user
sign_out user
Hope this helps.
If you are using Devise you could use the below in your rails console. This works perfect for me as in my app if you are using only 1 session per user account. I am storing my sessions in redisDB.
user = User.first
user.update_attributes(unique_session_id: "")
All I had to do was clear my users unique_session_id for that user and rails kicks the user out of the session.
But for multiple sessions for the same User account this does not work.
If you want to clear all user sessions you can do the below from terminal
rake db:sessions:clear
To sign_in by Devise check this way in console:
$ rails console
include Warden::Test::Helpers
def sign_in(resource_or_scope, resource = nil)
resource ||= resource_or_scope
scope = Devise::Mapping.find_scope!(resource_or_scope)
login_as(resource, scope: scope)
end
def sign_out(resource_or_scope)
scope = Devise::Mapping.find_scope!(resource_or_scope)
logout(scope)
end
#user = User.find(1)
sign_in #user
Then open http://127.0.0.1:3000/users/sign_in to test, in my case it will bypass this page and go to home page! Same to sign_out!
You may be able to use the helpers that others have mentioned after including the necessary module:
include Devise::Controllers::SignInOut
source: Module: Devise::Controllers::SignInOut
There's also another SO question where someone shares a method that doesn't involve using Devise helpers here.
I'm not a fan of the sign_out #user pattern because, at least for the devise version I'm using, that signs out the current user, regardless of the argument I pass it. If you're storing sessions in your database then you can do this:
#user.update_attributes(current_sign_in_token: "")
TBH I don't think that's the best way to do it, but it's the best way I've seen in my own research.
I believe you can simply update the password_salt and it will invalidate the user session on their next request.
user = User.first
user.update_column(:password_salt, 'reset')
Reference:
http://www.jonathanleighton.com/articles/2013/revocable-sessions-with-devise/
For old devise versions
Seems attribute tokens save sessions:
user.tokens = nil
user.save
You can create a logout link in views->layouts->application.html.erb as:-
<= link_to 'Log Out', destroy_user_session_path, method: :delete %>
It worked for me - hope it does for others as well.

Rails 4.1: access current_user in ActionMailer::Preview

Rails 4.1 has a nice way to preview mailers with ActionMailer::Preview. All of my mailers take a user parameter, and I would like to pass in current_user (from Devise) for the preview.
If I try this, it doesn't work.
class SubscriptionsMailerPreview < ActionMailer::Preview
# Preview this email at http://localhost:3000/rails/mailers/subscriptions_mailer/new
def new
SubscriptionsMailer.new(current_user)
end
end
It returns undefined local variable or method 'current_user' for #<SubscriptionsMailerPreview:0xa6d4ee4>.
I suspect this is because current_user is defined by Devise in ApplicationController, and according to the docs, ActionMailer uses AbstractController::Base. In that case, would storing current_user in a class variable be a bad idea?
Does anyone know how I can use the current_user helper in ActionMailer::Preview?
What would happen if you move your mailer job to the background? How would you get the current user then?
The mailer and its preview should not know about the current_user. The mailer's job is to send the mail to a user it receives. The preview is there to visually demonstrate its behaviour.
Create a new user in your mailer preview, and pass it to the mailer.
def new
user = User.create! # etc...
SubscriptionsMailer.new(user)
end
It doesn't matter who the user is. It matters that it's a user object.
If you want to test that the application will send a mail to the current_user, write a functional test for that.
You are right method defined in Controller won't be available in helper.
These posts can help you:
Where do I put helper methods for ActionMailer views? Access helpers from mailer?
https://www.ruby-forum.com/topic/168949

Rails 4 Devise Multiple User Models STI

I am using Devise and Rails 4. I want to add multiple User Models(admin, usertype1, usertype2) such that they inherit from the main User Model. I have searched many posts and come to the conclusion that I may use CanCan, which I do not want, or I may use Single Table Inheritance.
The way I see it is to add a type string-column to my main User model I created with Devise. I will also need to extend each sub-class from the parent as in:
class Admin < User
end
class Usertype1 < User
end
class Usertype2 < User
end
My question is: what do I do next? How exactly do I know how to access the type column? Do I also need to override the Devise Controller for the current_user helper method such that I can have current_admin for example?
I'm not sure this really answers the original question. I am trying to set up multiple session controllers for Devise, and it seems like it really does require multiple models for this use case. Will post back when I've got a working version.
You can also use the easy_roles gem. It is available on github. This gem provides a bitmask solution for your different user roles. You just must have one model, e.g User, this model gets an attribute "role". Just checkout the docs on github.
Devise + easy_roles + CanCan is a very good setup, it is very convenient in my opinion. I use this quite often.
Link to github: https://github.com/platform45/easy_roles
STI will give you current_admin, current_user1 and current_user2 Devise methods.
In application_controller.rb, create a custom current_user method like this:
def current_user
if current_admin
current_admin
elsif current_user1
current_user1
else
current_user2
end
end
helper_method :current_user
You will need some work on routes.rb and a custom sessions_controller.rb. See the accepted answer here Rails: Using Devise with single table inheritance

RSpec accessing application_controller methods such as 'current_user'

I'm trying to stub out a method on my current_user (using a modified restful_authentication auth solution) with rspec. I'm completely unsure of how I can access this method in my controller specs. current_user by itself doesn't work. Do I need to get the controller itself first? How do I do this?
Using rails 2.3.5, rspec 1.3.0 and rspec-rails 1.3.2
# my_controller_spec.rb
require 'spec_helper'
describe MyController do
let(:foos){ # some array of foos }
it "fetches foos of current user" do
current_user.should_receive(:foos).and_return(foos)
get :show
end
end
Produces
NoMethodError in 'ChallengesController fetches foos of current user'
undefined method `current_user' for #<Spec::Rails::Example::ControllerExampleGroup::Subclass_1::Subclass_1::Subclass_2::Subclass_2:0x7194b2f4>
rspec-rails gives you a controller method for use in controller examples. So:
controller.stub!(:current_user).with(:foos).and_return(foos)
ought to work.
how can it know where to find current_user? this should solve it:
subject.current_user.should_receive(:foos).and_return(foos)
I'm not entirely familiar with restful_authentication, just Authlogic and Devise, but it's probably similar in that current_user is a controller method and not an object, which is why calling should_receive on it isn't working as expected (you're setting an expectation on the object that current_user returns, but the method isn't accessible inside the scope of your expectation).
Try this:
stub!(:current_user).and_return(foos)
I read this and tweaked mine a bit. If you simply want to pass in a user object into your Rspec test, you can use this:
First, create a user object within the rspec test. For example:
(use whatever attributes you need or are required to create the user object.)
user = User.create(name: "ted")
(Note: you can also use a factory from FactoryGirl.)
Now, with that user object which is saved into the variable "user", do this within that same Rspec test:
controller.stub!(:current_user).and_return(user)
that should work...

Resources