2014年6月27日金曜日

2-4 ビューの役割

レンダリングの仕組み

HTMLによるUIだったり、APIの返り値だったり。簡単なビューはrenderメソッドで描かれる。

テンプレートの検索

 テキスト通りに画面表示がされず、しばらくハマってしまった。ちくしょう。
 htmlファイルと自分が考えているものは実際はerbファイルで、パラメータによりそれぞれhtmlが生成されるのでテンプレートファイルと言うみたい。結果的にはhtmlファイルと同じ。同じというか最後にhtmlになる。
 URL問い合わせ→routes.rb→アクション→テンプレートという順で何を画面に表示するか決定する。

renderを省略した場合

 アクションの定義として、render :showと表現していたが、コントローラ、アクション名、ビューのファイル名が規約通りに決められていれば、renderは省略できる。
 何をしたらどんな恩恵が受けられるかわかっていないから、この素人を混乱させるような気がする。早く覚えろよってことなんでしょうけど。優しいのか優しくないのかよくわからない。

コンテンツのタイプによって表示を出し分ける

 コントローラのアクション定義として下記のようなことを書けば拡張子によって応答させるファイルが使い分けられるらしい。
 例として出ているCSVファイルを書き出す方法はどこかで使えそう。例えば、/books/1.csvへ問い合わせれば、csvファイルのダウンロードという形で応答がある。
def show
@book = Book.find(params[:id])
respond_to do |format|
format.html
format.csv
format.json
end
end
 元々はコントローラ名/アクション名.フォーマット.エンジンという規約てテンプレートを探しにいく。
 例外的に処理をさせたい場合は下記のようrenderメソッドのオプションを使う。p78参照。
format.xml { render xml: @book }
 リダイレクトもできる。
redirect_to books_path
redirect_to books_path, status: :found #ステータスコードやシンボルも渡せる

partialテンプレートとlayout

 テンプレートは、基本的にまずviews/layouts/application.html.erbを読み、yieldに街頭アクションテンプレート(show.html.erbとか)が埋め込まれ、必要なところでpartialテンプレートを読む。
 partialテンプレートはlayouts内に配置するが、sharedフォルダを作って入れておくのが一般的?ファイル名はpartial以外と混同しないように、先頭にアンダースコアを入れる決まり。
<%= render partial: 'form' %>
 formがファイル名になるが、コード上はアンダースコアを入れない。実ファイル名には入れる。_form.html.erbとか。

variantsによるテンプレートの切り替え

 Rails4.1からは接続端末の種別に合わせたテンプレートを応答させることができる。
 以下はiPhoneから接続するとvariantに:mobile値が返され、show.html+mobile.erbを応答ファイルとして使用します。
class ApplicationController < ActionController::Base
before_action :detect_mobile_variant
  private
  def detect_mobile_variant
  request.variant = :mobile if request.user_agent =~ /iPhone/

end

ヘルパーの利用

 ビューを表示するときに、長い数値を3桁区切りにするとか、ちょっとした変換、一手間が必要なときは組み込みヘルパーを使えってよ。
 パラメータからURLを生成するurl_for、フォーム作成form_tag、フォーム操作form_for等。headで宣言に使われていたstylesheet_link_tagやjavascript_include_tagもヘルパーなんですって。やっと謎が解けた。
<%= url_for(controller: :books, action: :show, id: 1) %>
#=> /books/1
これだと、ある程度ルーティングが変更されても、ここが吸収してくれていちいちメンテナンスしなくてすみそう。
 オブジェクトの後に続いてないし、これはクラスメソッドの関数版と思えばいいのかな。予約関数というか。古い脳の持ち主としては、こういう書式だとなんかしっくりきますね。
 予約されているヘルパーで間に合わない場合は、独自のヘルパーを作成することもできる。app/helpers/application_helper.rbへモジュールを書き足せば、アプリケーション内のビューから利用できるようになる。
 コントローラごとに使用する場合には、books_helper.rbとコントローラを利用したファイル名にすればよい、と。また規約ですか。
 えらい人に、また規約ですね、と聞いたらこれは規約じゃないとか言われることもあって、その線引きがわからない。全体を理解して初めて線引きがわかるというのもどうかと思う。

エスケープ処理

クロスサイトスクリプティング(XSS)という攻撃を回避するためにエスケープという処理、対策をRailsでは実装している。
 エスケープされると困る場合には、以下のようにrawを使って回避できる。
<%= raw "<script>alert('sample');</script>" %>
多重エスケープで表示が崩れてしまう場合にrawが使えるようなことが書いてあるけど、ちょっとまだよくわからない。今はXSSにちょっとした対策をしていることだけ覚えておこう。

APIサーバにとってのビューについて

しばらく、書いていて意味の分からないことが続いている。ちょっと頑張ります。
 特にスマートフォンでは、スマホアプリからサーバの情報を持ってくる場合があったりして、RailsアプリケーションがHTTP APIとして振る舞う必要が求められるケースが多くなってきている。入力していてよくわからない。死ねる。んーと、WEBサーバーって読み替えちゃっていいのかな…。
 例えとしてJSONが出てきたけど、これもわからない。わからないけど、jbuilderというのがそのアプリケーションらしい。Gemfileにはすでに書かれていた。
 jbuilderの場合には、app/view/books/show.jbuilder.jsonというファイルをテンプレートとして使う。わからないけど作った。
 ん、作ったけどbooks/1.jsonでアクセスできず。Template is Missingと言われてしまっている。ルーティングもアクションも問題無さそうだけど…。
 ・・・見本としてscaffoldしたときのデフォルトファイルを見てみると、show.jbuilder.jsonじゃなくてshow.json.jbuilderだった!(初版 p89)えー。テキストのミスかい?それであたしから半日くらい奪ったのかい?あんまりわからなくてTwitterやYoutubeやYahoo知恵袋のアホな質問をいくつも見てしまったよ!やっと進める。でもなにやっていたか忘れちゃった。
 というか、scaffoldってすごいね。バカの一つ覚えでscaffold〜チューニングという流れで自分のやりたいような簡単なことは全部できそうな気がするな。
 ちなみに上で大変な目にあってできたことは以下の通り、たったこれだけ。
json.extract! @book, :id, :name, :price, :created_at #show.json.jbuilder
{"id":1,"name":"Book 1","price":1000,"created_at":"2014-06-25T07:04:24.117Z"} #画面出力
なんかどっと疲れが出た。なにも食べてないからたい焼き食べる。たい焼き食べた後、疲れてウトウトしてしまった。
 使ったサンプルを一応載せるけど、JSONについてのうまい説明が無くてアホな私にはどんな時に使うべきかがピンとこなかった。とりあえず存在だけ忘れないようにしておこう。スマホが相手のときには必要になるんだろうか。
json.extract! @book, :price
json.name_with_id "#{@book.id} - #{@book.name}"
json.publisher do
  json.name @book.publisher.name
  json.address @book.publisher.address
end
unless @book.high_price?
  json.low_price true
end
 high_priceメソッドが未定義だと怒られてしまったけど、2-2でファイル内に打ち込んでいなかった模様。

0 件のコメント:

コメントを投稿