Crafting Rails4 Applications読み回 7. Managing Application Events with Mountable Engines
-
Upload
masato-mori -
Category
Software
-
view
941 -
download
1
description
Transcript of Crafting Rails4 Applications読み回 7. Managing Application Events with Mountable Engines
Crafting Rails4 Applications
7. Managing Application Events with Mountable Engines
morimorihoge
この章で解説すること• 大きなテーマは三つ– Mountable Engineによって汎用性の高い機能をmountする様なコードを書く• Chap. 5でやったのは Engineそのものを extendしていたが,もっとうまくやれるぜ
– ActiveSupport::Notificationによる Railsの提供する pub/sub event API
– Rack middlewareの仕組みと内部構造• Railsのバックエンドを覗いてmiddlewareを作りつつ動きを見るぜ
Mountable/Isolated Engines
• 独自に Engineを Extendすると・・・– Routing namespace等が共有されるため,名前の衝突が怖い• rake routesしたときに, Engine拡張して作った plugin routesなのか,アプリ用に作った routesなのか分からなくなる
• HelperやらModelも同様• Mountable Engineを使うと– アプリ側の routerと別々の名前空間で routingが使える
• Isolated Engineを使うと– model/controller/view/assets/helperを pluginの名前空間内に閉じ込められる
とりあえず rails plugin new• --mountableオプションを付ける
--mountableあり
--mountableなし
Rails.application.routesを直接拡張しないようになる
Mountable engine
アプリ側で mountする
これで /mongo_metrics以下にmountable engineの routesが組み込まれる
Mountable engine
Routing的にも別々( Engine別)に表示される
mountの内部• routingの内部的には get/post/put/delete/
resources/resource等は全てmatch()のwrapper• mount()はそもそも挙動が全く別物で, Engineを指定 URL以下に指定し,処理をブン投げる
pp.142env[“SCRIPT_NAME”]/env[“PATH_INFO”]から /mongo_metricsを削除してEngineに投げることで,MongoMetrics::Engine内部ではそもそも/mongo_metrics部分は見えない(元アプリ側の参照はmain_app()で取得可能)
Mountable engine
Namespace IsolationIsolated engine
Pluginの Engine側に isolate_namespaceを記述することで, Engine内で使うクラスが自動的に namespaceを補完する様になる
pp.133
ActiveSupport::Notifications API• よくある pub/sub式の event API
– Publish : ActiveSupport::Notifications.instrument(event_name, payload)• Blockを渡すと Block部分の時間が subscriberに通知される
– Subscribe: ActiveSupport::Notifications.subscribe(event_name)
pp.133
pp.134※instrumentは全ての subscriberに通知されるLoggerなんかで使われることを想定
Notifications API
MongoDB/Mongoid gem
• MongoidはMongoDBを楽に使うためのGem
• Mongoid::Documentをincludeし, store!を実装すれば良いよ!
MongoDB/Mongoid
MongoMetrics::Engineの実装MongoMetrics::Engine
普通の Railsアプリの様に実装して良いが,MongoMetrics moduleに入れる必要があることに注意( Isolated Engine)
(以下略)
Routingは普通の Railsアプリの様に書ける
テストコードMongoMetrics::Engine
適当な Routing呼び出しをさせれば Notificationが飛ぶので, test/dummy以下で$ rails new controller Home foo bar bazしておく
main_appでアプリ側を参照できる
Rack BasicsRack
Rackの基本・リクエストを call()に投げる・ callの返値は [STATUS_CODE, HEADER, RESPONSE_BODY]・ RESPONSE_BODYは eachを実装していること
config.ru
pp.141
config.ruがあるディレクトリで$ rackupすれば Rack serverが起動する( -sでWeb serverを選べる)
Rack on RailsRack
Railsの config.ru
Rails Routerと RackのカンケイRack
Config/routes.rbはこんな書き方ができる
Rackの call(env)メソッドそのもの
toが文字列の場合,自動的に呼び出し先を変換している.”post#index”なら以下の Controller.action()を返す( action()の戻り値は call()を実装している)
Rack middlewareRack middleware stack
rake middlewareRack middleware stack
インストールされたミドルウェア一覧を取得できる rakeコマンド
この順序を眺めながらメシが食える(上に行くほど先に適用される)
rake middlewares (1)Rack middleware stack
rake middlewares (2)Rack middleware stack
Adding Rack Middlewares
Rack middleware stack
Controllerで任意のmiddlewareを使うには, useすれば良いだけ
MuteMiddleware
Rack middleware stack
MongoMetricsはそのままだと全てのアクセスに対してログを記録してうるさいので,それを黙らせるmiddlewareを作る
こんな感じでブロックでmuteさせたい
MuteMiddleware
Rack middleware stack
特に何事も無い感じの実装
MuteMiddlewareをどこに入れるか?Rack middleware stack
MuteMiddlewareをインストールするRack middleware stack
MongoMetricsの Engineではデフォルトmute
アプリケーション側ではMuteしたいもので個別にmute
必要の無い dependencyを減らすGem optimization
Gemspecに railsの dependencyを書くと, ActionMailerや ActiveRecordなど, pluginに本来必要無い gemも dependしてしまう
Dependencyを個別に書くことで, pluginの依存関係はすっきりする# ただし,これをやると dummyアプリケーションの方で ActionMailerや ActiveRecord# に依存する部分の定義を外さないとテストが通らなくなるので注意
pp.149
Streaming plugin
Another sample of plugin development
MongoMetricsのデータを CSV streamingで出すぜ
Content-Lengthを削除することで streamingになる
詳細は pp.151辺りを参照.見ればわかります
Rack-level v.s. Rails-level
Another sample of plugin development
Streaming的なことは, Rack middlewareレベルで書くこともできる
Rackアプリとして #eachを streamingぽく返す様に作れば streamingで返せる
Rack-levelで実装した方がmiddlewareの読み込み数が減るのでオーバーヘッドは小さいが, Rails-levelで実装した方がデータサイズに応じた処理などがやりやすい.どっちで実装すべきかは実装時に考えましょう
まとめ• Mountable/Isolated Engineの説明をして,
Mountableな Engineを含むMongoMetricsプラグインを作成したよ!
• Rack middlewareの挙動を追いかけてmiddleware chainを覗いたよ
• 使わない gem dependencyを削って最適化したよ!やったね!