1. fujimura

    Posted

    fujimura
Changes in title
+Railsで同じパスでログイン状態に応じて別の画面を表示する賢い方法
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,53 @@
+ほとんどこの記事の要約です。
+
+User-centric Routing in Rails 3 // Collective Idea | Crafting web and mobile software based in Holland, Michigan
+http://collectiveidea.com/blog/archives/2011/05/31/user-centric-routing-in-rails-3/
+
+例えばアプリケーションのルート(e.g. `http://example.com`) で、ログイン時はマイページ、非ログイン時はランディングページを表示したい。そういう時はどうすればいいでしょうか。
+
+ビュー内で分岐、コントローラーでビューを出し分ける、同じパスで出すことを諦める、などの解決策がありますが、もうちょっと賢い方法がありました。
+
+Railsでは、特定の条件を満たした時のみルーティングを行う、ということができます。`id`が期待される部分は数字のみ、というように正規表現を使ったりする場合がよくあるパターンだと思いますが、これ、実は`#matches?`というメソッドを実装したクラスを渡すことで制限をかけることもできます。この機能を使って、`/`にアクセスした時、`current_user`のセッションがある時は`MyPageController#index`、ない時は`LandingPageController#index`にルーティングする、ということが可能です。
+
+渡されたクラスは[`request`](http://api.rubyonrails.org/classes/ActionDispatch/Request.html)オブジェクトと共にインスタンス化されるので、`matches?`メソッドの中で`session`を触ることもできます[^request]。
+
+[^request]: `#session`メソッドは`Rack::Request`に実装されていて、`ActionDispatch::Request`は`Rack::Request`を継承している
+
+実装例は下記の通りです。
+
+config/routes.rb
+
+```rb
+Rails.application.routes.draw do
+ # 前略
+
+ # セッションがない時
+ # Rails 4では`as` を使って別名を当てる必要があります。Rails 3では不要かも(試してません)
+ root 'public#index', as: :public_root, constraints: LoggedInConstraint.new(false)
+ # セッションがある時
+ root 'home#index', constraints: LoggedInConstraint.new(true)
+
+ # 後略
+end
+```
+
+条件判定用のオブジェクトは何でもいいのですが、[Structのメンバー名を指定してサブクラスを作る機能](http://docs.ruby-lang.org/ja/2.3.0/method/Struct/s/=5b=5d.html)を使って実装されていました。これ便利。
+
+app/constraints/logged_in_constraint.rb[^constraint]
+
+[^constraint]: 場所は別に`/app/constraints`でなくても大丈夫です。
+
+```rb
+class LoggedInConstraint < Struct.new(:value)
+ def matches?(request)
+ request.session.key?('current_user_id') == value
+ end
+end
+```
+
+
+参考URL
+
+- Rails Routing from the Outside In — Ruby on Rails Guides http://guides.rubyonrails.org/routing.html#advanced-constraints
+- User-centric Routing in Rails 3 // Collective Idea | Crafting web and mobile software based in Holland, Michigan
+http://collectiveidea.com/blog/archives/2011/05/31/user-centric-routing-in-rails-3/