How to trigger action when rails session expires? - ruby-on-rails

I have a user who can login to my Ruby on Rails application. I wrote the functions myself with an sessions controller. I also set a time in session_store.rb when the session should expire.
This all works fine, But additionally I want to track when users login or logout. Right now I can trace the login and logout when it's done manually by the user. But when a session expires my "sessions#destroy" option is not triggered and therefore no logout time is set.
Is there any possibility to trigger an action when the session expires or when a session is killed by rails?
Thanks!
UPDATE:
Sorry, I should have included some of my code:
app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
def new
if !current_user.nil?
redirect_to start_path
end
end
def create
user = User.find_by_username(params[:username])
if user && user.authenticate(params[:password])
session[:user_id] = user.id
UserTracing.create(user_id: user.id, sign_in_at: DateTime.now)
redirect_to start_path, notice: I18n.t("text logged_in")
else
flash.now.alert = I18n.t("error username_or_password_invalid")
render "new"
end
end
def destroy
#id = current_user.id
session[:user_id] = nil
UserTracing.where(user_id: #id).order(sign_in_at: :asc).last.update_attributes(sign_out_at: DateTime.now)
redirect_to root_url, notice: I18n.t("text logged_out")
end
end

This is easy.
All you have to do is use your sessions helper method to
Create a time when the session is set to expire
sessions[:expires_at] = Time.now + minutes_to_run * 60
Create a function that retrieves this time.
Have a function in your controller that is run before this page is loaded to check if the current time is greater than the time the session was set to expire. The solution uses javascript setTimeout() to ensure the page is refreshed otherwise you would have to wait for the user to reload. This way your app refreshes the page.
Here's a blog post that details this idea.
https://medium.com/#thatlovelypract/rubyonrails-timed-session-a5de0cf70f3b

Related

Are Cookies in Rails Site based (app based)?

I have decided to deal with sessions in my application on a cookie level, so I have a session controller that looks like:
module Xaaron
class SessionsController < ApplicationController
def new
end
def create
user = Xaaron::User.authenticate_user(params[:user_name], params[:password])
if sign_in(user)
if params[:remember_me]
cookies.permanent[:auth_token] = user.auth_token
else
cookies[:auth_token] = user.auth_token
end
flash[:notice] = "Welcome back, #{user.first_name}."
redirect_to root_path
else
flash[:alert] = "You have entered incorrect credentials."
redirect_to login_path
end
end
def destroy
cookies.delete(:auth_token)
redirect_to root_path
end
end
end
My application is kind of a "gate keeper" application so the user can login into say site.com and from there go to product1.site.com, their information such as user name, api key, all that jazz is shared between these two apps via promiscuous gem.
How ever my question is:
is the cookie created in site.com viable for use in product1.site.com thus allowing me to use specific helper methods such as: current_user in product1.site.com to see if said user is logged in?
The purpose for this is that if user A is not signed into site.com they cannot access product1.site.com
RFC 6265 has the answer in section 4.1.2.3. If the cookie domain attribute is set to dom.ain, then the cookie is sent by the user agent when making requests to dom.ain, www.dom.ain, sub.dom.ain, and other subdomains of dom.ain. You can control the cookie domain attribute via the domain key in the cookies hash, like this
cookies.signed[:secure_session] = {domain: 'dom.ain', value: "#{user.salt}#{user.id}"}

Submit form after devise login

I'm trying to let users submit a reservation request without being logged in. After they submit unauthed users are prompted to sign in or sign up. After signing up I'd like the form to be submitted and the (new registered) users to be taken to the checkout page.
Store location keeps the last page to return users after logging in. I need to figure out how to continue users on their intended path by submitting their forms and placing them on the checkout page after sign up/ sign in.
def store_location
#stores the last url. Used for post-login redirects to what the user was trying to do last.
if (!request.fullpath.match("/users/") && !request.xhr?) # don't store ajax calls
session[:previous_url] = request.fullpath
end
end
Ok, I think this is pretty dirty but I haven't been able to find another way to do this.
after_sign_in_path_for is a method Devise calls that allows you to send people to different pages after sign in.
I took all the create logic out of the controller and put it into a service object.
def after_sign_in_path_for(resource)
if session[:booking_params].present?
#booking = Booking::CreateBooking.new(user:current_user, params: session[:booking_params]).return_booking
checkout_booking_path(#booking.public_id)
else
session[:previous_url] || root_path
end
end
In the controller, the create method is split into two parts. If there is no current user I save their params into the session and they are sent to login. If there is the CreateBooking service object is called normally.
def create
if current_user.nil?
session[:booking_params] = params
redirect_to new_user_registration_path
else
#booking = Booking::CreateBooking.new(user:current_user, params:params).return_booking
respond_to do |format|
format.html { redirect_to checkout_booking_path(#booking.public_id) }
end
end
end
In the after_sign_in_path_for method I check for the session params and create the booking there.
Let me know if there is a better way to do this!

Possible to pass a record through Rails redirect_to?

I'm attempting to manage user sign ups and log in with omniauth. I'd also like to collect more information about users after they authorize with the provider. At the moment Vendor#from_omniauth returns either an existing vendor or a new Vendor record with their auth hashes already populated. Is it possible to pass along the new record to the Vendor controller so the form can easily use it?
I'm using Rails 4.
class SessionsController < ApplicationController
def create
vendor = Vendor.from_omniauth(env["omniauth.auth"])
if vendor.new_record?
redirect_to new_vendor_url(vendor)
else
session[:vendor_id] = vendor.id
redirect_to root_url, notice: "Signed in!"
end
end
end
This issue was resolved by changing new_vendor_url(vendor) to new_vendor_url(vendor: vendor.attributes).
HTTP is stateless, so you'll need to either include info in the params, in the session (via cookies or other), or in the database.
Given that you seem to be doing a registration process, I might be inclined to put the info in the database as soon as you get it. It's an additional write and then read, but if the user drops out midway through the process, you can still contact them (in theory) to resume the signup.
Pass the vendor.id to as an argument to new_vendor_url, then do the lookup in the rendered action:
# app/controllers/sessions_controller.rb
redirect_to new_vendor_url(:vendor_id => vendor.id)
# app/controllers/vendors_controller.rb
def new
vendor_from_session = Vendor.find(params[:vendor_id])
# code here
#vendor = Vendor.new
end

Tracking request before redirecting

App has a lot of tests, and issue is that only authenticated users can view them. So when there are not, app redirects them to sing_in/login_as_guest page. For example user sings in or logs in as guest, after that I want to redirect them to the page they were actually going to.
But I have no idea from where to begin, and is this possible?
Can you please give me a key from where to begin?r
Here's an example:
class UserController < ApplicationController
def login
if User.authenticate(params[:user][:email], params[:user][:password])
referer = params[:referer] || session[:referer] || request.referer
flash.notice = 'Login succeeded'
redirect_to referer || root_path
else
flash.alert = 'Login failed'
redirect_to user_login_path
end
end
end
Now when you want to redirect back from somewhere, just add a referer path to either a param, the session or the request, and it will redirect back on success.
the end of chapter 5 and chapters 6,7,8,9 are step by step guide of what you need exactly
rails tutorial
Ok, I found the simple solution, works pretty well for me. Application controller:
if #current_permission.allow?(params[:controller], params[:action])
return true
else
redirect_to root_url
session[:was_going]=request.path #here I start session if request causes redirection
end
end
This method returns that request, if it exists
def root_or_request
if session[:was_going]
path=session[:was_going]
session[:was_going] = nil
return path
else
return root_url
end
end
And than after starting session I just redirect with calling this method.

How to force a user login on an action and then execute it later

I am trying to force a user to login once they call this update action in my article controller (I am trying to work with gradual engagement) but once they login, I want to still call this action instead of halting.
def update
#article.attributes = params[:article]
#article.save
#store this article as a session variable
session[:pending_article] = #article.body
respond_with(#article, :location => article_url(#article))
end
Right now I am using a before_filter for the action that requires the user to login
def require_user
unless current_user
store_location
flash[:notice] = "You must be logged in to access this page"
redirect_to login_url
return false
end
end
However, I understand that before filters halt the original action once they redirect, so update never gets called. Basically, I want a user to be logged in to save an article but I want to save their work so I'm storing the article body in a session variable which I grab later. Is there a better way to require a user to login for an action but call it afterwards anyway?
In your require_user method you can do something like this:
session[:article] = params[:article]
Then in your login method (/sessions/create?) do this:
# this should take you back /articles/new,
# you may have to move your call to store_location
# or manually set session[:return_to]
redirect_back_or_default
Then in ArticlesController#new
def new
#article = Article.new(session[:article] || {})
end
Then the saved article params from the session are still there so the form is pre-filled out.
Be careful storing too much content in the session though. In Rails the default session store is a cookie, and cookies only hold about 4k of data. You may need to change your session store to pull this off.

Resources