RailwayJS ハマりポイント① filterの使い方
RailwayJSを3週間近くいじって、少しはまりやすいところについて解説したいと思います。
まず、filterというのはcontrollerのアクションの前後で動作する処理のことで、具体的にはログイン済みであることを要求するページにアクセスする際にログイン済みかを判定し、ログインしていたらそのまま処理を続行、していなかったらログインページにリダイレクトさせる、などの処理をfilterとして書くと、同じくログインを要する別のアクションからもそのfilterを使うことでコードの重複を防ぐことができます。
通常、ログインを要求する、のようなfilterはapplication全体で共有したいので、application_controllerに書くわけです。
◯application_controller.coffee
before 'set current user', -> User.find req.cookies.user_id ,(err,user)=> if err || !user? @current_user = null console.log "user not found" else @current_user = user console.log "user found" next()
こうすると、すべてのアクションでこのfilterが呼ばれます。やっている処理は、cookieからuser_idを取得、findして存在していたら@current_userに値をセット、存在しないならnullを入れておくという処理です。これですべてのアクションから@current_userを使用することができます。
ここで、RoRと違う点として、最後にnext()を書く必要があるのが重要です。next()は処理をもとのアクションに戻すために使います。redirectするか、next()しない限り次の処理には永遠に戻らないので注意してください。(試してないけどたぶんrender()でもいいと思う)
このように@current_userをセットするだけならすべてのactionに対して実行していいわけですが、「ログインしていなかったらログインページにリダイレクトする」というような処理はactionごとに指定しないといけません。このような場合はapplication_controllerにfilterを用意して、それをそれぞれのcontrollerから呼び出す必要があります。
◯application_controller.coffee
requireAuthenticate = ()-> ・・・・(※1) if @current_user == null flash 'error', 'You must login for continue' redirect path_to.new_session else next() publish('requireAuthenticate', requireAuthenticate)
◯hoge_controller.coffee
load 'application' before(use 'requireAuthenticate'), {only: ['index','....] } action 'index', .....
ここで新しくpublishとuseというのがでてきました。通常、あるcontroller(基本的にはapplication_controllerになるだろう)を取り込む場合は、load関数を使用します。
load 'application'
とした時点で、application_controller自体でbefore定義されているもの(上の例だと'set current user')はフィルタとして機能します。一方で、関数として定義されているけど、filterとして登録されていないもの(上の例だと'requireAuthenticate')はloadした上で明示的にbefore指定する必要があります。
ただ、controllerをまたぐ場合はpublish関数によって公開しないとアクセスができません。だからこのように
publish(' 登録名', 関数)
としてapplication_controllerで指定した上で、それぞれのcontrollerから
load 'application' #=> application_controllerをloadする
before(use 'requireAuthenticate') #=> requireAuthenticate(publish時の登録名)を取得し、before登録する。
という処理が必要なんですね。
このへん(publish,use)はRailsにはない考えです。
なぜならRailsではそれぞれのcontrollerがすべてapplication_controllerのサブクラスで、application_controller中で定義されたものはスーパークラスのメソッドとしてアクセスしますが、RailwayJSではapplication_controllerは親クラスではないから、どちらかというとモジュールです。
RailwayJSでは基本的にcontrollerは優秀ですね。使い方に一度慣れてしまえば、さほどRailsと使用感は違わないのではないのでしょうか。
※1...ここが->でなく=>となっているのはthisのコンテクストを変更しているため。これが->だともとのアクションとはthisが異なって、インスタンス変数にアクセスできなくなる。