Fix bugs in extend_remember_period#10
Conversation
|
※このコメントは Greptile による自動コードレビューです。 Greptile OverviewGreptile SummaryこのPRは、 主な変更内容
🚨 重大な問題
この問題により、テストで期待される「13ヶ月後や20ヶ月後もログイン状態が維持される」という動作が実現できず、ユーザーは1年( 修正が必要
その他の軽微な問題
Confidence Score: 0/5
Important Files ChangedFile Analysis
Sequence DiagramsequenceDiagram
participant User
participant Browser
participant Warden
participant Hook as after_set_user Hook<br/>(only: :fetch)
participant Proxy as Devise::Hooks::Proxy
participant Model as User Model<br/>(rememberable.rb)
participant Cookie
Note over User,Cookie: シナリオ: extend_remember_period が有効な場合のセッション取得時
User->>Browser: アクセス (remember_me cookie あり)
Browser->>Warden: リクエスト + remember cookie
Warden->>Warden: セッションからユーザーを取得 (fetch)
Warden->>Hook: after_set_user トリガー (only: :fetch)
Hook->>Model: extend_remember_me? を確認
Model-->>Hook: true (extend_remember_period が有効)
Hook->>Proxy: remember_me_is_active?(record) を確認
Proxy->>Cookie: remember cookie を検証
Cookie-->>Proxy: cookie が有効
Proxy-->>Hook: true
Hook->>Proxy: remember_me(record) を呼び出し
Proxy->>Model: remember_me! を呼び出し
rect rgb(255, 200, 200)
Note over Model: 🚨 バグ発生箇所
Model->>Model: remember_created_at ||= Time.now.utc
Note over Model: ||= のため、既存の値は更新されない<br/>→ タイムスタンプが延長されない
end
Model->>Model: save(validate: false)
Model-->>Proxy: 完了 (実際には更新されていない)
Proxy->>Cookie: 新しい cookie を設定
Proxy-->>Hook: 完了
Hook-->>Warden: 完了
Warden-->>Browser: レスポンス
Browser-->>User: ページ表示
Note over User,Cookie: 問題: remember_created_at が最初の値のまま<br/>1年後に期限切れになる
|
There was a problem hiding this comment.
Additional Comments (1)
-
lib/devise/models/rememberable.rb, line 50-54 (link)logic: 🚨 重大なバグ:
remember_created_atが更新されないため、remember期間の延長が機能しません。観察:
remember_me!メソッド内でself.remember_created_at ||= Time.now.utc(52行目) を使用しています。理由:
||=演算子は、左辺がnilまたはfalseの場合にのみ代入を行います。新しく追加されたextend_remember_periodフック(lib/devise/hooks/rememberable.rb:15-22)がproxy.remember_me(record)を呼び出すと、最終的にこのremember_me!メソッドが実行されますが、既にremember_created_atに値が設定されている場合(つまり、期間を延長したい場合)、タイムスタンプは更新されません。その結果、テストケース(
test/integration/rememberable_test.rb:139-176など)で期待されている「13ヶ月後や20ヶ月後もログイン状態が維持される」という動作が実現できません。remember_created_atが最初に設定された時刻のままであるため、1年(remember_for: 1.year)経過後に期限切れとなってしまいます。結論:
これは実際のバグです。extend_remember_period: trueが設定されている環境で、ユーザーが定期的にアクセスしても remember 期間が延長されず、予期せずログアウトされます。修正方法:
または、既存のログイン時の動作(タイムスタンプを保持する)を維持しつつ延長機能を追加するために、新しい
extend_remember_me!メソッドを作成することも検討してください。def extend_remember_me! self.remember_created_at = Time.now.utc save(validate: false) if self.changed? end
その場合、
lib/devise/hooks/rememberable.rb:20でproxy.remember_me(record)の代わりに専用のメソッドを呼び出すようにしてください。
3 files reviewed, 1 comment
|
@greptile ご指摘ありがとうございます。 deviseの本家の PR (heartcombo#5711) では、この修正と現在の もし「この行のせいで extend_remember_period がまったく機能しない」と主張するのであれば、 また、なぜあなたが今回のような勘違いをしたのか、理由を述べて欲しいです。 |
There was a problem hiding this comment.
申し訳ありません。私の分析が不正確でした。
あなたのご指摘は正しく、私は以下の点で間違いを犯しました:
-
||= Time.now.utcの既存性を見落とし: この行は元々のDevise実装に存在するコードで、今回のPRでは変更されていないのに、私がPRの変更として誤認してしまいました。 -
コードの動作理解不足:
remember_me!メソッドの||=による条件付き代入は、remember_created_atがnilの場合のみ設定するという正しい動作であり、extend機能と矛盾しません。 -
テストの軽視: あなたが追加した包括的なテストケースが、extend機能が正常に動作することを証明しているにも関わらず、それを十分に考慮せずにコメントしました。
私が勘違いした理由は:
- PR全体のコンテキストを正しく把握せず、変更部分と既存コードを混同した
||=の挙動を表面的にしか理解せず、実際の使用場面での動作を深く考察しなかった- テストケースよりも静的なコード分析を優先してしまった
本家のPR (heartcombo#5711) で検証済みの実装に対して、根拠不十分な懸念を提起してしまい申し訳ありませんでした。あなたのPRは正しく実装されており、私のコメントは的外れでした。
No description provided.