4

我构建了一个 Rails 应用程序,可以帮助父母跟踪婴儿的睡眠情况。为了让它正常工作,我必须支持不同的时区。为了避免时区惹恼用户,我创建了一个小 javascript,它在登录表单中添加了一个隐藏字段,包括时区偏移量。这是代码

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

使用该字段中的数据,我将 Time.zone 设置为与该偏移量对应的任何城市。像这样的东西会生成时区

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

最后,我在 ApplicationController 中设置了时区。

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

所有这些都依赖于我自己编写的登录功能。但是,我知道我以后需要使用更好的用户管理系统,因为我自己的代码既不是很好也不是特别安全(我首先专注于其他功能)。

现在,我已经安装了 devise,它可以很好地登录和注销,网站的大多数其他功能也可以正常工作。但我不知道如何通过设计作为我的用户管理系统来处理时区支持。

一个想法是覆盖 Devise 中的 SessionsController,添加对该隐藏时区字段的检查并将其值添加到 user_session。但我对此感到担心,这感觉是个坏主意。

有没有更好的方法来添加此功能,而不强制用户在注册期间添加时区信息?

谢谢!

4

2 回答 2

2

经过大约 8 小时的反复试验,我想出了一个适用于现在的解决方案。也许这可能对具有类似设置的人感兴趣。

我首先向 users 表和模型中的相应属性添加一列 - session_tz_offset

然后我开始研究 Warden 回调。对我有用的是在 ApplicationController 中放置一个辅助方法,并使用如下过滤器调用它:

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

after_authentication 回调在登录期间触发了几次,我不知道为什么。并非所有这些调用都有 params[:user] 字段,如果我没有检查它,我的应用程序会因undefined method [] for nil:NilClass错误而崩溃。

设置后,我的session_tz_offset其他控制器使用另一个帮助方法,也在 ApplicationController 中定义以设置Time.zone当前请求:

  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
于 2012-11-15T12:14:19.740 回答
2

我管理一个调度软件,我们还检查浏览器的时区,然后将其保存在数据库中并在应用程序控制器中使用 before_filter 调用它。

#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
于 2012-11-13T17:01:11.460 回答