I have an application in which I used the tutorial offered by http://ruby.railstutorial.org/chapters/a-demo-app?version=3.0#sec:planning_the_application and http://ruby.railstutorial.org/chapters/sign-in-sign-out#sec-signin_failure (Rails 3.2) to create my user and session model.
I want to implement a expiration if user is in-active for 5 minutes or so. I have tried:
config.timeout_in = 5.minutes in my **application.rb**
and
config.session_store :cookie_store, key: 'blanked_out', :expire_after => 2.minutes in my **session_store.rb**
None of these seem to be working.
Any suggestions?
Sessions Helper
def sign_in(user)
cookies.permanent[:remember_token] = user.remember_token
self.current_user = user
end
def sign_out
self.current_user = nil
cookies.delete(:remember_token)
end
def current_user
#current_user ||= User.find_by_remember_token(cookies[:remember_token])
end
Did u try this?
EDIT:
MAX_SESSION_TIME = {enter time}
before_filter :verify_session
def verify_session
if !session[:expire].nil? and session[:expire] < Time.now
# Session has expired. Clear or reset session.
reset_session
end
# Assign a new expiry time, whether the session has expired or not.
session[:expire] = MAX_SESSION_TIME.seconds.from_now
return true
end
I came across the following while researching a CookieStore issue. I think it answers your question:
https://www.coffeepowered.net/2013/09/26/rails-session-cookies/
Here's the code Chris Heald suggests for adding session timeout with CookieStore (note this would go in your application_controller.rb file:
class ApplicationController
before_filter :validate_session_timestamp
after_filter :persist_session_timestamp
SESSION_TTL = 48.hours
def validate_session_timestamp
if user? && session.key?(:ttl) && session[:ttl] < SESSION_TTL.ago
reset_session
current_user = nil
redirect_to login_path
end
end
def persist_session_timestamp
session[:ttl] = Time.now if user?
end
end
Related
how to get session in helper file?
UserHelper.rb
module UsersHelper
def self.auth login, password
user = Users.where("firstname = :firstname AND password = :password", {:firstname => login, :password => password})
if user != []
return true
else
return false
end
end
def self.is_auth? level
puts #session
user = Users.where("firstname = :firstname AND password = :password", {:firstname => #session[:firstname], :password => #session[:password]})
if user != []
return true
else
return false
end
end
end
Admin_controller.rb
class AdminController < ApplicationController
include Rails.application.routes.url_helpers
def initialization
#session = session
end
def index
#session = session
if UsersHelper.is_auth?(2)
render :text => "ssssss"
end
end
def auth
if params[:send] != nil
if UsersHelper.auth params[:firstname], params[:password]
session[:firstname] = params[:firstname]
session[:password] = params[:password]
redirect_to :action => "index"
else
#error = 1
end
end
end
def exit
session.delete(:firstname)
session.delete(:password)
render :json => session
end
end
Error
undefined method `[]' for nil:NilClass
app/helpers/users_helper.rb:13:in `is_auth?'
app/controllers/admin_controller.rb:8:in `index'
Only Controller can access session.
So, in a nutshell, if you are going to use this method in Controllers only like what is you case, you can define it as ApplicationController's method. Or define it a module and include it in AppplicationController.
class ApplicationController < ActionController::Base
def auth
end
def is_auth?
end
end
If you want to use the method in both controller and view, just declare them as helper_method
class ApplicationController < ActionController::Base
helper_method :auth, :is_auth?
def auth
end
def is_auth?
end
end
Ref: http://apidock.com/rails/ActionController/Helpers/ClassMethods/helper_method
Another note: In my opinion it's really not worth the time to build auth system from scratch by yourself. The functionalities are not easy but quite general. There are well baked gems such as Devise, Authlogic. Better to use them.
I have a running Rails application, using ActiveAdmin and its models to autenticate users. Now I'm interested in moving to an ActiveDirectory authentication, so my users can validate wiht the domain's users.
I've been trying adauth and it looks like a great gem, but I'm a little bit lost when trying to "mix" this gem with my ActiveAdmin authentication. I'm pretty sure I'm not the first one in doing it, so any help would be appreciated.
Thanks!
I finally was able to manage to integrate AD in ActiveAdmin.
Here's what I did, in case someone is interested:
Include gem 'adauth' in your gems
Execute bundle install
Execute rails g adauth:config
Configure the config/initializers/adauth.rb for your AD connection. For example, if your domain is example.com, you must include:
c.domain = "example.com"
c.server = "IP address of your domain controller"
c.base = "dc=example, dc=com"
Execute rails g adauth:sessions
Modify your application_controller.rb. Mine was:
class ApplicationController< ActionController::Base
protect_from_forgery
helper_method :current_user
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
def authenticate_user!
if current_user.nil?
redirect_to '/sessions/new', :error => "Invalid Login"
end
end
end
Execute rails g adauth:user_model user install_adauth.
This creates the migration install_adauth, but for some reason it was empty. I had to fill it myself with:
class InstallAdauth < ActiveRecord::Migration
def up
create_table :users do |u|
u.string 'login'
u.text 'group_strings'
u.string 'name'
u.string 'ou_strings'
end
end
def down
drop_table :users
end
end
Execute rake db:migrate
Modify your sessions_controller.rb. Mine was:
class SessionsController < ApplicationController
def new
redirect_to '/admin' if current_user
end
def create
ldap_user = Adauth.authenticate(params[:username], params[:password])
if ldap_user
user = User.return_and_create_with_adauth(ldap_user)
session[:user_id] = user.id
redirect_to '/admin'
else
redirect_to '/sessions/new', :error => "Invalid Login"
end
end
def destroy
session[:user_id] = nil
redirect_to '/sessions/new'
end
end
So far the validation through ActiveAdmin still works. To switch to ActiveDirectory we must change the file initializers/active_admin.rb
# config.authentication_method = :authenticate_admin_user!
config.authentication_method = :authenticate_user!
#config.current_user_method = :current_admin_user
config.current_user_method = :current_user
In my case, I needed to restart Apache too.
If anytime we want to switch back to ActiveAdmin, we just need to undo the last change
I'm following the tutorial in Railscast to create a "forgot my password" link. I'm running into problems when creating a cookie for the password reset. Here is the error:
ArgumentError in PasswordResetsController#create
wrong number of arguments (1 for 0)
Rails.root: C:/Sites/application
Application Trace | Framework Trace | Full Trace
app/models/user.rb:37:in `create_remember_token'
app/models/user.rb:29:in `send_password_reset'
app/controllers/password_resets_controller.rb:7:in `create'
../app/models/user.rb - line 28 is remember_token(:password_reset_token)
before_save :create_remember_token
before_create { create_remember_token(:remember_token) }
def send_password_reset
create_remember_token(:password_reset_token)
save!
UserMailer.password_reset(self).deliver
end
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
../app/controllers/password_resets_controller.rb
class PasswordResetsController < ApplicationController
def new
end
def create
user = User.find_by_email(params[:email])
user.send_password_reset if user
redirect_to root_url, :notice => "Email sent with password reset instructions."
end
def edit
#user = User.find_by_password_reset_token!(params[:id])
end
end
../app/helpers/sessions_helper.rb
def sign_in(user)
cookies.permanent[:remember_token] = user.remember_token
current_user = user
end
def current_user
#current_user ||= user_from_remember_token
end
def sign_out
current_user = nil
cookies.delete(:remember_token)
end
private
def user_from_remember_token
remember_token = cookies[:remember_token]
User.find_by_remember_token(remember_token) unless remember_token.nil?
end
end
If I change the way I find the user in my controller to: user = User.find_by_email(params[:session][:email]) the first error dissapears. I can only think that this is telling me that I'm calling the user incorrectly, and not assigning the new token to it on reset.
Just looking at the Railscast, where you have the "remember_token" method, they use a "generate_token" method that was added to the User class. That kind of typo might not be the problem, of course, but if it were the error message would make sense (a method that didn't previously exist wouldn't expect any arguments).
i know it's a silly one but i want to know how can we create a current_user method to get access throughout the app without using any gem or plugin ? To test it i created an app that make a user able to share files and folders.How to create such method that a user can only access his folder and files?Here is my code sample:
Login controller:
class LoginController < ApplicationController
layout 'signup'
#to skip checking the authentication and authorization.
skip_before_filter :check_authentication, :check_authorization
def index
end
def authenticate
if request.post?
user = User.authenticate(params[:username],params[:password])
if user
session[:current_user_id]=user.id
session[:name]= user.first_name
puts "session name #{session[:name]}"
redirect_to(:subdomain => user.company.subdomain, :controller => :dashboard)
else
flash.now[:notice] = "Invalid user/password combination"
end
end
end
def destroy
session[:current_user_id] = nil
reset_session
flash[:notice] = "You have been successfully logged out."
redirect_to root_url
end
end
User model:
require 'digest/sha1'
class User < ActiveRecord::Base
#sharering method start
after_create :check_and_assign_shared_ids_to_shared_folders
#this is to make sure the new user ,of which the email addresses already used to share folders by others, to have access to those folders
def check_and_assign_shared_ids_to_shared_folders
#First checking if the new user's email exists in any of ShareFolder records
shared_folders_with_same_email = SharedFolder.find_all_by_shared_email(self.email)
if shared_folders_with_same_email
#loop and update the shared user id with this new user id
shared_folders_with_same_email.each do |shared_folder|
shared_folder.shared_user_id = self.id
shared_folder.save
end
end
end
#to check if a user has acess to this specific folder
def has_share_access?(folder)
#has share access if the folder is one of one of his own
return true if self.folders.include?(folder)
#has share access if the folder is one of the shared_folders_by_others
return true if self.shared_folders_by_others.include?(folder)
#for checking sub folders under one of the being_shared_folders
return_value = false
folder.ancestors.each do |ancestor_folder|
return_value = self.being_shared_folders.include?(ancestor_folder)
if return_value #if it's true
return true
end
end
return false
end
#sharing method end
def self.authenticate(name, password)
user = self.find_by_username(name)
if user
expected_password = encrypt_password(password, user.salt)
if user.hashed_password != expected_password
user = nil
end
end
user
end
#'password' is a virtual attribute
def password
#password
end
def password= (pwd)
#password =pwd
return if pwd.blank?
create_new_salt
self.hashed_password = User.encrypt_password( self.password, self.salt)
end
def self.users_in_company(user_id)
User.find(user_id).company.users
end
private
def password_non_blank
errors.add(:password, "Missing password, please enter your password") if hashed_password.blank?
end
def create_new_salt
self.salt = self.object_id.to_s + rand.to_s
end
def self.encrypt_password(password, salt)
string_to_hash = password +"prftnxt" + salt
Digest::SHA1.hexdigest(string_to_hash)
end
end
i want to access all files as "current_user.files" is it possible without any gem?
Application helper:
module ApplicationHelper
#for current user to use through out the app
def current_user
#current_user ||= session[:current_user_id] && User.find_by_id(session[:current_user_id]) # Use find_by_id to get nil instead of an error if user doesn't exist
end
end
Application controller:
class ApplicationController < ActionController::Base
include UrlHelper
#include ApplicationHelper
helper_method :current_user #make this method available in views
protect_from_forgery
# def current_user
# #current_user ||= session[:current_user_id] && User.find_by_id(session[:current_user_id]) # Use find_by_id to get nil instead of an error if user doesn't exist
# end
end
and in task controller:
class TasksController < ApplicationController
# GET /tasks
# GET /tasks.xml
def index
#menu = "Timesheet"
#page_name = "Manage Task"
company_id = Company.find_by_subdomain(request.subdomain)
#users = User.find_all_by_company_id(company_id)
#tasks = current_user.tasks.all#Task.all
#task = Task.new
respond_to do |format|
format.html # index.html.erb
format.html # new.html.erb
format.xml { render :xml => #tasks }
end
end
end
and my error message i got:
NameError in TasksController#index
undefined local variable or method `current_user' for #<TasksController:0xfa7e638>
that's not so hard ;) just define the method you need:
class ApplicationController < ...
def current_user
#current_user ||= session[:current_user_id] && User.find_by_id(session[:current_user_id]) # Use find_by_id to get nil instead of an error if user doesn't exist
end
helper_method :current_user #make this method available in views
end
Hi friends i have found the way to create current_user method without using any gem or plugin:
In my application_helper.rb i did this :
module ApplicationHelper
def current_user
User.find(session[:current_user_id])
end
end
and at the end in my application controller.rb i called this, because from here i can access it through the application:
class ApplicationController < ActionController::Base
include UrlHelper
include ApplicationHelper
helper_method :current_user
end
and now i can access any data related to current user:
like :
#tasks = current_user.tasks
Thanks to all my friends for their valuable answers.
I followed Railscasts #235 and #236 to setup creating user authentications with omniauth.
http://railscasts.com/episodes/235-omniauth-part-1
http://railscasts.com/episodes/236-omniauth-part-2
I have a 2 boolean attributes on the user model called :facebok_share and :twitter_share that I want to set to true when a new authentication is created.
I have this working for me when I create a new user, but if an existing user adds an authentication I cannot get the boolean to update to true.
When apply_omniauth(omniauth) is called it sets self.facebook_share = true or self.twitter_share = true in my user model.
I've tried to add a new method called apply_share which changes the booleans depending on provider, and I'm trying to call current_user.apply_share(omniauth) but nothing is happening in the database.
What am I doing wrong? Thanks!
## authentications controller
class AuthenticationsController < ApplicationController
def index
#title = "Authentications"
#authentications = current_user.authentications if current_user
end
def create
# creates omniauth hash and looks for an previously established authentication
omniauth = request.env["omniauth.auth"]
authentication = Authentication.find_by_provider_and_uid(omniauth['provider'], omniauth['uid'])
# if previous authentication found, sign in user
if authentication
flash[:notice] = "Signed in successfully"
sign_in_and_redirect(:user, authentication.user)
# for users already signed in (current_user), create a new authentication for the user
elsif current_user
current_user.apply_share(omniauth)
current_user.authentications.create(:provider => omniauth['provider'], :uid => omniauth['uid'], :token => (omniauth['credentials']['token'] rescue nil),
:secret => (omniauth['credentials']['secret'] rescue nil))
flash[:notice] = "authentications successful"
redirect_to authentications_url
# new user is created and authentications are built through apply_omniauth(omniauth)
else
user = User.new
user.apply_omniauth(omniauth)
if user.save
flash[:notice] = "Signed in successfully"
sign_in_and_redirect(:user, user)
# if validations fail to save user, redirects to new user registration page
# new twitter authentications redirect so user can enter their password
else
session[:omniauth] = omniauth
redirect_to new_user_registration_url
end
end
end
def destroy
#authentication = current_user.authentications.find(params[:id])
#authentication.destroy
flash[:notice] = "Successfully destroyed authentication."
redirect_to authentications_url
end
end
## user model
# set share booleans to true depending on 'provider' type
def apply_share(omniauth)
case omniauth['provider']
when 'facebook'
self.facebook_share = true
when 'twitter'
self.twitter_share = true
end
end
# from authentications controller, new user split into type of provider
def apply_omniauth(omniauth)
case omniauth['provider']
when 'facebook'
self.apply_facebook(omniauth)
when 'twitter'
self.apply_twitter(omniauth)
end
# builds authentication with provider, uid, token, and secret
authentications.build(hash_from_omniauth(omniauth))
end
protected
# sets new user attributes from facebook
def apply_facebook(omniauth)
self.name = omniauth['user_info']['name']
self.email = omniauth['user_info']['email'] if email.blank?
self.facebook_share = true
end
# sets new user attributes from twitter
def apply_twitter(omniauth)
if (extra = omniauth['extra']['user_hash'] rescue false)
# Example fetching extra data. Needs migration to User model:
# self.firstname = (extra['name'] rescue '')
self.name = (extra['name'] rescue '')
self.bio = (extra['description'] rescue '')
end
self.twitter_share = true
end
# set authentication attributes to those from 'omniauth' hash
def hash_from_omniauth(omniauth)
{
:provider => omniauth['provider'],
:uid => omniauth['uid'],
:token => (omniauth['credentials']['token'] rescue nil),
:secret => (omniauth['credentials']['secret'] rescue nil)
}
end
end
## new methid with :before add => :apply_share
def apply_share(authentication)
case authentication['provider']
when 'facebook'
self.facebook_share = true
when 'twitter'
self.twitter_share = true
end
self.save
end
I believe your never actually saving current_user. So your setting your attributes to true, and then redirecting. The association is stored in the authentication model, so Rails, trying to be helpful, doesn't update current_user, just the new instance of authentication
try:
current_user.apply_share(omniauth)
current_user.save
and see if that fixes it. Now if it does, I would strongly recommend using a callback instead. Take a look here:
http://guides.rubyonrails.org/association_basics.html
Section 4.5 about association callbacks. You can do a before_add callback on your has_many authentications assocation to remove that code from your controller as its getting pretty bloated as is.
class User < ActiveRecord::Base
has_many :authentications, :before_add => :apply_share
def apply_share(authentication)
#update attributes
#save model
end
end
You need to call #save on the User object after setting the *_share attributes.
Adding new items to a has_many collection automatically saves the collection item, but does not trigger a save operation on the parent (belongs_to).