Necesito limpiar la sesión después de cierto tiempo rails.
Por especificación >>, ésto se puede hacer con
reset_session
pero no me parece buena práctica ligar el fin de la sesión a una acción en específico: ¿qué pasa si el usuario abandona la app a mitad de camino?
Si implementamos la sesión en la cookie ésto no nos preocupa, ya que no nos supone memoria extra…
Pero en mi app necesito borrar los archivos que haya subido de mi servidor, o sino me iré llenando de archivos que no son de nadie.
Además, así le doy la opción al usuario de volver atrás e intentar varias veces con el mismo archivo, sin que tenga que subirlo a cada vez.
filtro
Googleando un poco >>, salta a la vista que necesitaré usar filtros para lograrlo >>
En app/controllers/app_controller.rb escribiremos un before_filter que antes de cada request guarde registro de cuando fue la última vez que se vió al usuario
#todos los controllers heredan de éste #por tanto este filtro se aplica a todos los request class ApplicationController < ActionController::Base before_filter :last_seen private def last_seen if session[:last_seen] < 20.minutes.ago then #mi lógica reset_session end session[:last_seen] = Time.now end end
Aquí, antes de reset_session, puedo ejecutar la lógica que quiero de limpiar directorios, etc.
whenever
Éso soluciona el fin de sesión siempre y cuando el usuario vuelva – de hecho, ¿no debiera entonces extendérsela? – Lo importante es ir limpiando los directorios si el usuario nunca más se vió.
Ésto lo haremos con una gema llamada whenever – que de hecho creo que ya viene en rails (scheduler.rb?): no, no está – que ofrece una sintaxis ruby para configurar el cron del sistema.
Simplemente la agregamos en el Gemfile
gem 'whenever'
y luego de
bundle install
ejecutamos
wheneverize
para crear config/schedule.rb donde…
Ahora, como necesito los datos de la sesión para limpiar los directorios de las que están expiradas, no me sirve que las sesiones se guarden en las cookies – como es el default – sino que tener acceso a ella desde el tarea que ejecutaré periódicamente.
active_record_store
Entonces requiero que las sesiones se guarden en la base de datos. Para ésto, modificamos el archivo config/initializers/session_store.rb
MiApp::Application.config.session_store :active_record_store
y luego ejecutamos
rails generate session_migration
para generar la migración que crea la tabla de sesión y
rake db:migrate
para crearla.
rake
Con éstose podré usar whenever para ejecutar un rake (o un método de un modelo usando rails runner). Utilizaré la primera de las opciones porque me parece más consistente – justamente es una tarea lo que quiero hacer.
En lib/tasks creo un un archivo cuyo nombre termine en .rake para que sea incluído al Rakefile.
Dentro defino una task así
namespace :db do namespace :sessions do desc "Limpia los directorios de las sesiones expiradas" task :expire => :environment do #tiene acceso a Rails Rails.logger.info "Limpiando sesiones..."#logueo tiempo = 10.minutes.ago.to_s(:db) sql = "DELETE FROM sessions WHERE updated_at < "+tiempo ActiveRecord::Base.connection.execute(sql)#borro sesiones expiradas end end end
Si queremos ejecutarlo, de acuerdo a sus <em>namespace</em>, podemos llamarlo
rake db:sessiones:expire
Y es el que ejecutaremos desde el archivo scheduler.rb que vimos más arriba
every 1.days do rake "db:sessions:expire" end
Para que el cron se haga efectivo, ejecutamos
whenever -w -s environment=development
(ojo con la opción -s, donde seteamos el RAILS_ENV a development – o el que se esté usando – ya que sino actuará en otra base de datos)
y efectivamente estaremos limpiando las sesiones periódicamente.