ruby on rails - rails - Establecer la zona horaria del usuario de forma dinámica con el diseño
rspec rails devise (2)
Creé una aplicación de rieles que ayuda a los padres a llevar un registro del sueño de sus bebés. Para que funcione correctamente, he tenido que admitir diferentes zonas horarias. Para evitar molestar al usuario con husos horarios, he creado un pequeño javascript que agrega un campo oculto al formulario de inicio de sesión, incluido el desplazamiento de la zona horaria. Aquí está el código
var timeZoneField = $("input[name=''user_tz_offset'']");
if (timeZoneField.length) {
var browserDate = new Date();
var timeZoneOffsetSeconds = (browserDate.getTimezoneOffset() * 60) * -1;
$(timeZoneField).val(timeZoneOffsetSeconds);
}
Con los datos de ese campo configuro Time.zone a cualquier ciudad que corresponda con ese desplazamiento. Algo así genera la zona horaria
user_time_zone = ActiveSupport::TimeZone.[](params[:user_tz_offset].to_i)
session[:user_time_zone] = user_time_zone
Finalmente, configuré la zona horaria en ApplicationController.
def set_user_time_zone
if (session[:user_id])
Time.zone = session[:user_time_zone]
else
Time.zone = config.time_zone
end
end
Todo esto depende de la funcionalidad de inicio de sesión, que yo misma escribí. Sin embargo, sabía que necesitaría utilizar un mejor sistema de administración de usuarios más adelante, ya que mi propio código no está bien hecho o es particularmente seguro (antes me enfocaba en otra funcionalidad).
Ahora, he instalado el dispositivo y funciona bien para iniciar y cerrar sesión, la mayoría de las funciones del sitio también funcionan. Pero no sé cómo acercarme al soporte de zona horaria con el diseño como mi sistema de administración de usuarios.
Una idea es anular el SessionsController en Devise, agregar un control para ese campo de zona horaria oculta y agregar su valor a user_session. Pero siento aprensión por hacerlo, parece una mala idea.
¿Hay una mejor manera de agregar esta funcionalidad sin forzar al usuario a agregar información de zona horaria durante el registro?
¡Gracias!
Administro un software de programación y también verificamos la zona horaria del navegador, pero luego solo la guardamos en la base de datos y la llamamos con un before_filter en el controlador de la aplicación.
#Application Controller
before_filter :set_time_zone
private
def set_time_zone
if current_user
Time.zone = current_user.time_zone if current_user.time_zone
end
end
Después de aproximadamente ocho horas de prueba y error, he encontrado una solución que funciona por ahora. Quizás esto pueda ser de interés para alguien con una configuración similar.
Comencé agregando una columna a la tabla de usuarios y el atributo correspondiente en el modelo - session_tz_offset
.
Luego comencé a hackear devoluciones de Warden. Lo que funcionó para mí fue poner un método auxiliar en ApplicationController, y llamarlo con un filtro anterior como este:
before_filter :authenticate_user!, :set_session_tz_offset_for_user
helper_method :set_user_time_zone, :set_session_tz_offset_for_user
def set_session_tz_offset_for_user
Warden::Manager.after_authentication do |user, auth, opts|
if (params[:user])
user.session_tz_offset = params[:user][:session_tz_offset]
user.save
end
end
end
La devolución de llamada after_authentication se dispara varias veces durante el inicio de sesión, por qué me es desconocido. No todas estas llamadas tienen un campo params [: usuario], y si no lo comprobé, mi aplicación se bloqueó con un undefined method [] for nil:NilClass
error undefined method [] for nil:NilClass
.
Cuando se establece session_tz_offset
, mis otros controladores usan otro método auxiliar, también definido en ApplicationController para establecer Time.zone
para la solicitud actual:
def set_user_time_zone
if (user_signed_in?)
if(user_session[:time_zone])
Time.zone = user_session[:time_zone]
else
user_session[:time_zone] =
ActiveSupport::TimeZone.[](current_user.session_tz_offset)
Time.zone = user_session[:time_zone]
end
else
Time.zone = config.time_zone
end
end