- 更新日: 2014年3月9日
- Rails
ユーザーのタイムゾーンを自動で保存するコードをリファクタリング
昨日のエントリー、Rails でユーザーのサインアップ時にタイムゾーンを自動で判定して保存 | EasyRamble で書いたコードがどうにも気持ち悪いので、リファクタリングを行いました。
自動でユーザーのタイムゾーンを設定するために、モデルから request 変数にアクセスするために書いたコードだったのですけど、やはりモデルが request 変数にアクセスする設計はどう考えても良くないですので。
request をスレッドローカル変数にする部分を削除
app/controllers/application_controller.rb
1 2 3 4 5 |
before_filter :set_request_filter def set_request_filter Thread.current[:request] = request end |
以上の部分のコードは削除しました。
タイムゾーンのクッキーを引数で渡すように変更
タイムゾーンが保存されているクッキーを、User.get_user_timezone に引数で渡すように変更しました。
app/controllers/users/regsitrations_controller.rb
1 2 3 4 5 6 |
def build_resource(hash=nil) hash[:time_zone] = User.get_user_timezone(cookies["timezone"]) # ... super end |
controller からなので、普通に cookies で timezone クッキーを取得できます。
User.get_user_timezone の実装を変更
User.get_user_timezone メソッドが、timezone_cookie を引数で受けとるように変更。
app/models/user.rb
1 2 3 4 5 |
def self.get_user_timezone(timezone_cookie) timezones = ActiveSupport::TimeZone::MAPPING.select{ |k, v| v == timezone_cookie }.keys timezone = timezones.select{ |t| t == timezone_cookie.gsub("_", " ").split("/").last }.first || timezones.first || "UTC" timezone end |
引数で渡された timezone クッキーを使うように、User.get_user_timezone メソッドの実装を変更しました。
当初の Thread.current[:request] を用いた実装は、OmniAuth で Twitter/Facebook で認証したユーザーを保存するクラスメソッドの兼ね合いから、ああいう実装にしていました。詳しくは、以下エントリーの User.find_for_twitter_oauth, User.find_for_facebook_oauth を参照。
Rails でユーザーのサインアップ時にタイムゾーンを自動で判定して保存 | EasyRamble
cookie だけをスレッドローカル変数にせず、request をスレッドローカル変数にしていたのは、他に request.env[‘HTTP_ACCEPT_LANGUAGE’] にもアクセスするため。タイムゾーンとともに、ユーザーの言語も HTTP_ACCEPT_LANGUAGE で判定して自動で保存するコードを書いていましたので。
なので、Twitter/Facebook の OAuth 認証ユーザーにもタイムゾーンを自動で保存する場合は、User.find_for_twitter_oauth, User.find_for_facebook_oauth がタイムゾーンを保存したクッキーを引数に取るように変更する必要があります。ユーザーの言語も自動設定する場合は、request.env[‘HTTP_ACCEPT_LANGUAGE’] も引数渡しにする。
cookie や HTTP_ACCEPT_LANGUAGE を controller から引数で渡して、model に定義したメソッドを呼び出すことになるので、Thread.current[:request] を用いるより、コードが若干ごちゃごちゃになってしまいます。しかし、モデルから request にアクセスするという気持ち悪さは解消できます。どちらが良いか断定できませんので、ベストプラクティスを知りたいところです。
- Rails の関連記事
- RailsでMySQLパーティショニングのマイグレーション
- Rails ActiveRecordでdatetime型カラムのGROUP BY集計にタイムゾーンを考慮する
- RailsプラグインGemの作成方法、RSpecテストまで含めたrails pluginの作り方
- RailsでAMPに対応するgemをリリースしました
- Railsでrequest.urlとrequest.original_urlの違い
- Railsでwheneverによるcronバッチ処理
- Google AnalyticsのRails Turbolinks対応
- Railsアプリにソーシャル・シェアボタンを簡単設置
- Rails監視ツール用にErrbitをHerokuで運用
- Facebook APIバージョンのアップグレード手順(Rails OmniAuth)
Leave Your Message!