Slide 1

Slide 1 text

Cra$ing  Rails4  Applica0on   Masatoshi  Iwasaki 6.  Wri0ng  DRY  Controllers   with  Responders

Slide 2

Slide 2 text

概要 •  カスタムのResponderを使うことでよりDRYにコ ントローラが書ける。   •  ScaffoldのテンプレートをカスタムResponder 用にカスタマイズするとさらにDRYになる。   •  (青字になっている箇所は発表者注です。)  

Slide 3

Slide 3 text

Introduc0on •  Scaffoldのコードはちょっと冗長。   – 繰り返し大杉。   – 特にrespond_to周辺。   •  これをrespond_withを使うことでさくっとDRYな 感じにできる。  

Slide 4

Slide 4 text

Scaffold的なコントローラ

Slide 5

Slide 5 text

respond_with使うとDRYに書ける

Slide 6

Slide 6 text

Ac0onController::Responder •  この辺をまとめて引き受けてるのが Responder。   •  自分でResponderを定義することでさらにいろ んなことができる。

Slide 7

Slide 7 text

本章のゴール •  2種類のResponderを作る。   – 1)HTTPリクエストに対して適切なキャッシュを返 すResponder   – 2)Flashを管理するResponder。  

Slide 8

Slide 8 text

Responderを理解する

Slide 9

Slide 9 text

HTTP  verbs(method) •  ResponderはHTTP  verbs(HTTPメソッド)と密接 に関連してる。   •  Responderが具体的にどういうメソッドにどう 対応しているかを見ていく。   •  なぜかここではRESTという単語が出てこない がで、本章後半で説明される。   •  Railsで開発してると当たり前な説明なので HTP  verbsの結論までは省略。    

Slide 10

Slide 10 text

要するにこんな感じ •  Naviga0onalはHTMLで返す場合の対応   •  APIはJSONやXMLで返す場合の対応  

Slide 11

Slide 11 text

寄り道:RESTとは •  Representa0onal  State  Transferの略   •  Roy  Fieldingsの博士論文で提唱された。   –  “Architectural  Styles  and  the  Design  of  Network-­‐based   So$ware  Architectures”  (2000)   •  PDFとHTMLで公開されてる。   –  博士論文ということもあって前半は過去の研究のまと めで分量がヘビー。   –  一見シンプルでさくっと思いつきそうにみえるRESTも 実際は様々なアーキテクチャを踏まえた上でのウェ ブにおける解だということが分かる。   •  HTTP  1.1とURIをデザインに影響を与えた。  

Slide 12

Slide 12 text

寄り道:RESTで何が良くなった? •  HTTP  1.0ではRFCで定義されていたのはGET,   HEAD,  POSTだけ。   – PUTやDELETEなどはaddi0onal  feature扱い。   •  HTTP  1.1でRESTで使われているPUT,  DELETE などが追加された。   – 元々URLに指定されたHTMLを取ってくるだけだっ たプロトコルがURIとHTTPメソッドによってサー バー上のリソース管理をできるように拡張された   – (と、いうことが画期的だったんだと思う)。  

Slide 13

Slide 13 text

Responderの呼び出し   インターフェース •  Callメソッドを持っていて引数を受け取れれば いいだけ。   – 引数は呼び出し元のコントローラ、リソース、オプ ションの3つ。   •  newしてすぐrespondメソッドが呼ばれる。    

Slide 14

Slide 14 text

Responderのメソッド •  やってることは単純。   •  to_htmlとto_jsだけ 定義されていて、他 はsendで to_hogehogeを呼び 出すだけ。  

Slide 15

Slide 15 text

Responder#to_html •  テンプレートをレンダリングしようとして、な かったらnaviga0on_behaviorを呼ぶ。  

Slide 16

Slide 16 text

Responder#naviga0on_behavior •  この動きが先ほど出てきたHTTP  verbsとの対 応関係に沿っている。

Slide 17

Slide 17 text

Responder#to_format •  こっちもテンプレートなかったらapi_behaviorを 呼ぶ。   •  エラーがちゃんとされていればdisplay_errors のほうに行く。  

Slide 18

Slide 18 text

Responder#api_behavior •  こちらもHTTP  verbsに対応している。   – else以下はupdateやdestroyでテンプレートがない 場合で、そのときはno_contentらしい。  

Slide 19

Slide 19 text

Responder#display •  FormatはURIで指定された形式(index.jsonなど)   •  Formatはini0alizeでcontrollerから読み込んでいる。  

Slide 20

Slide 20 text

Respond_withでのオプション指定 •  respond_toと同様に特定のケースでは上書きできる。   –  これがさっき出てきた Responder#to_formatの default_render。  

Slide 21

Slide 21 text

Responderの読み込み方 •  特定のコントローラでも。   •  config/applica0on.rbなどから。  

Slide 22

Slide 22 text

Flash  Responderを作る というか具体的なコードみないとよく分からん。

Slide 23

Slide 23 text

Flash  Responderのゴール •  ScaffoldでcreateとupdateでFlashだすけど、 処理は同じだからResponderにいれてしま え。   – でも文言は完全に一緒じゃないのでI18nで参 照できるようにしておく。   •  まずはおきまりのplugin作成。  

Slide 24

Slide 24 text

とりあえずTDD 至って普通のscaffold向け。Destroyでもエラーを出すようにしてる。

Slide 25

Slide 25 text

Dummyアプリでのscaffold作成 •  普通のRailsアプリと同様に作ります。

Slide 26

Slide 26 text

Responderを使うように変更 •  当然scaffoldは responderを使うように なってないので respond_toを respond_withに変える。   •  Flashの記述をコント ローラから消したので、 テストはこける。

Slide 27

Slide 27 text

Flash  Responderの実装開始 •  まずcreateから。   •  Createが成功したら   – flash.users.create.no0ceを表示。   •  Createが失敗したら   – flash.users.create.alertを表示。  

Slide 28

Slide 28 text

こんな感じに実装 •  I18nのスコープ 作るところだけ がちょっとやや こしい。

Slide 29

Slide 29 text

I18n_lookupを詳しく見る たとえば、createが成功してstatusがno0ceの場合、scopeも含めて探す翻訳 のパスと、見つからなかったときのデフォルトパスは以下のようになる。     欲しい物:  flash.users.create.no0ce   デフォルト:  flash.ac0ons.create.no0ce     なお、最後の引数のresource_nameは翻訳テキストのプレースホルダに対応 する。  

Slide 30

Slide 30 text

従ってこんな感じのyamlを作る

Slide 31

Slide 31 text

Responderをコントローラに •  ここではアプリ全体で標準のresponderにしている。   •  翻訳ファイルも同時にload_pathに読み込ませてい る。  

Slide 32

Slide 32 text

テスト書く •  I18n.backend.store_transla0onsでデフォルトの 翻訳文を上書きして、その上書きした文章が flashに出るかどうかというテストをしている。  

Slide 33

Slide 33 text

でもこける •  Destroy出来ないときのエラーなので。。。   •  Destroyしようとしたらエラーにするようにしない とだめ。   •  ここであえてdestroyでエラーが返る例にしているの は、HTTP  verbsの説明でDELETEメソッドでもfailureに なるケースがあることに触れていたためと思われる。  

Slide 34

Slide 34 text

HTTP  Cache  Responderを作る

Slide 35

Slide 35 text

REST •  Railsは1.2の頃からRESTを利用している。   – API作るのに便利。   •  だけど、APIの実装と同時にパフォーマンス の最適化が必要になる。   •  ブラウザからリソースを生成した後、何回か 読み取るケースがあるが、その都度同じレ スポンスを返すのは非効率。   – これをブラウザ側のキャッシュで対応したい。  

Slide 36

Slide 36 text

寄り道:RESTでのキャッシュ •  $がキャッシュ(cashとかけてる)。   •  Server+CacheとClient+Cacheの二種類が共存できる。   From:  Architectural  Styles  and  the  Design  of  Network-­‐based  So$ware  Architectures    

Slide 37

Slide 37 text

ブラウザキャッシュ •  HTTP  1.1のLast-­‐Modified/  If-­‐Modified-­‐since ヘッダを使ってリソースが更新されてなけれ ばペイロードを空にしてヘッダだけ返す。

Slide 38

Slide 38 text

実装方針 •  If-­‐Modified-­‐Sinceが含まれないリクエストの場 合、通常のレスポンスにLast-­‐Modifiedヘッ ダーを付与。   •  If-­‐Modified-­‐Sinceが含まれていてリソースが 更新されていなければ、304コードを返してレ スポンスのbodyは空。   •  If-­‐Modified-­‐Sinceが含まれていてリソースが 更新されていれば、通常のレスポンスにLast-­‐ Modifiedヘッダーを付与。

Slide 39

Slide 39 text

図にするとこんな感じ 特にRailsではアセット系のファイルで効果大。更新頻度が低くて参照頻度の高いHTMLは   サーバー側キャッシュとサーバー構成をうまくやることでRailsのプロセス自体へのアクセス を抑えることができるのもポイント。  

Slide 40

Slide 40 text

この辺の話については •  「ハイパフォーマンスWebサイト」がおすすめです。   –  「サービス遅いからってサーバーサイドだけ速くすれ ばいいってもんじゃねぇぞ」的な。   –  今となっては基本中の基本。  

Slide 41

Slide 41 text

んでTDD •  さっきの実装 方針をその まんまテスト に落としただ け。  

Slide 42

Slide 42 text

Resopnders#HipCacheを作る •  RailsはHTTP  cacheをうまく扱うヘルパーメソッ ドをすでに持っているので、それらを使う。

Slide 43

Slide 43 text

こんな感じ •  シンプルに渡された リソースの最終更 新時間をチェックし ている。  

Slide 44

Slide 44 text

細かく見ていく(to_format) •  to_formatのところでHTTP  cacheのハンドリン グをかぶせてる。  

Slide 45

Slide 45 text

細かく見ていく(do_hip_cache?) •  Perform_cachingが有効で、かつGETの場合 のみ対応。  

Slide 46

Slide 46 text

細かく見ていく(do_hip_cache!) •  Request.fresh?  はこんな感じ。  

Slide 47

Slide 47 text

細かく見ていく(max_0mestamp) •  実際のサービスのindex  ac0onあたりではこん なresourcesのupdated_at見るとかするよりSQL 叩いた結果とかを使いたい場合のほうが多い と思われる。

Slide 48

Slide 48 text

そして組み込む •  これでテストが通った。  

Slide 49

Slide 49 text

Generatorのカスタマイズ

Slide 50

Slide 50 text

Scaffoldのテンプレート変えちゃえ •  Responderの仕様を前提にすれば、最初から flashやrespond_toのところをrespond_withだ けに一本化できる。   •  だったら、scaffold生成時に出来るコントロー ラのテンプレートを変えてしまえばいい。

Slide 51

Slide 51 text

Scaffoldのカスタマイズ方法 •  2種類ある。   – Scaffold  generatorを作る。   – Scaffold用のテンプレートを変更する。   •  今回は後者でいく。   •  前者の方法はすでに4章で取り上げたためと 思われる。  

Slide 52

Slide 52 text

Scaffoldテンプレートの上書き •  Rails  generatorにこんなコードがある。   – ってことはコピー元のファイルを変えればいい? •  source_pathの存在   –  Generatorは複数のパスを見ることが出来る。   –  パスを追加してそちらを優先させればいい。   •  幸い、lib/templatesを優先してみるように作られてい る。  

Slide 53

Slide 53 text

Rails::Generatorsを読む •  controller.rbというファイルがコントローラのテ ンプレートだと分かる。

Slide 54

Slide 54 text

カスタムテンプレートを   生成するようにする

Slide 55

Slide 55 text

カスタムテンプレートを   生成するようにする

Slide 56

Slide 56 text

テンプレートを詳しく •  ERBを使ってDSLっぽくなっている。   – orm_classが対象となるモデル名。   •  plural  /  singular  はこの手の奴でよく出てくる。

Slide 57

Slide 57 text

テンプレートを詳しく •  set_リソース名 で  @user  =  User.find的なもの を定義。   •  64行目はStrongParameters用のメソッド。

Slide 58

Slide 58 text

Generatorのインストール •  これでカスタムtemplateがデフォルトになる。

Slide 59

Slide 59 text

GeneratorのORM  Agnos0cism   (ORM不可知論) •  さっき出てきたorm_classの話。   – ORMがAc0veRecordからMongoidとかいろいろ変 わったらどうする?   •  ORMが変わっても対応できるような機構が Railsに用意されている。  

Slide 60

Slide 60 text

Ac0veModelの例 •  さっきの   <%=  orm_class.find  %>     はこれを使っていた。  

Slide 61

Slide 61 text

例:DataMaper •  findに相当するメソッドをgetに変えている   •  これにより、datamapper  gemをインストールし た後、今回のpluginをインストールしても scaffold  templateはそのままでいい。  

Slide 62

Slide 62 text

まとめ •  Responderがどう動いているか、どうカスタマ イズすればいいかを学んだ。   •  HTTP  cacheとflash  メッセージのハンドリングを responderで実装した。   •  今回実装したのはCondi0onal  GET。   •  Condi0onal  PUTというものもあるよ。   – リソース更新時に最終更新日が変わっていたら 409  Conflictを返す。