Edited at

Railsで同じパスでログイン状態に応じて別の画面を表示する賢い方法

More than 3 years have passed since last update.

ほとんどこの記事の要約です。

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オブジェクトと共にインスタンス化されるので、matches?メソッドの中でsessionを触ることもできます1

実装例は下記の通りです。

config/routes.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のメンバー名を指定してサブクラスを作る機能を使って実装されていました。これ便利。

app/constraints/logged_in_constraint.rb2

class LoggedInConstraint < Struct.new(:value)

def matches?(request)
request.session.key?('current_user_id') == value
end
end

追記:

こっちのほうが簡単だった!

http://qiita.com/sue738/items/976c8abf4aa8e530899f

参考URL





  1. #sessionメソッドはRack::Requestに実装されていて、ActionDispatch::RequestRack::Requestを継承している 



  2. 場所は別に/app/constraintsでなくても大丈夫です。