Set user time zone dynamically with devise

时光毁灭记忆、已成空白 提交于 2020-01-03 18:04:34

问题


I've built a rails app that helps parents keep track of their infants’ sleep. For it to work properly I've had to support different time zones. To avoid annoying the user with time zones, I've created a little javascript that adds a hidden field to the login form, including the timezone offset. Here's the code

var timeZoneField = $("input[name='user_tz_offset']");
  if (timeZoneField.length) {
    var browserDate = new Date();
    var timeZoneOffsetSeconds = (browserDate.getTimezoneOffset() * 60) * -1;
    $(timeZoneField).val(timeZoneOffsetSeconds);
  }

With the data from that field I set the Time.zone to whatever city corresponds with that offset. Something like this generates the timezone

user_time_zone = ActiveSupport::TimeZone.[](params[:user_tz_offset].to_i)
session[:user_time_zone] = user_time_zone

Finally, I set the time zone in the ApplicationController.

def set_user_time_zone
  if (session[:user_id])
      Time.zone = session[:user_time_zone]
  else
    Time.zone = config.time_zone
  end
end

All this relies on the login functionality, which I wrote myself. However, I knew that I would need to use a better user management system later, as my own code is neither well done or particularly secure (I was focusing on other functionality first).

Now, I've installed devise and it works well to log in and log out, most other functions of the site work as well. But I don't know how to approach the time zone support with devise as my user management system.

One idea is to override the SessionsController in Devise, add a check for that hidden time zone field and add its value to the user_session. But I feel apprehensive about doing so, it feels like a bad idea.

Is there a better way to add this functionality, without forcing the user to add time zone information during registration?

Thank you!


回答1:


I manage a scheduling software and we also check the browser's timezone but then just save it in the database and call it with a before_filter in the application controller.

#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



回答2:


After about eight hours of trial and error I have come up with a solution that works for now. Perhaps this may be of interest to someone with a similar setup.

I started by adding a column to the users table and corresponding attribute in the model – session_tz_offset.

Then I started hacking around with Warden callbacks. What worked for me was to put a helper method in the ApplicationController, and call that with a before filter like this:

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

The after_authentication callback fires several times during login, why is unknown to me. Not all of these calls have a params[:user] field, and if I didn't check for it, my application crashed with a undefined method [] for nil:NilClass error.

When the session_tz_offset is set, my other controllers use another helper method, also defined in ApplicationController to set Time.zonefor the current request:

  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


来源:https://stackoverflow.com/questions/13360875/set-user-time-zone-dynamically-with-devise

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!