【Rails:2】コントローラとビュー
HTTPの基礎
- HTTP::ブラウザとサーバが情報を送受信するための通信手段
- リクエスト(ブラウザがサーバに送る要求)
GET /ctr_name/index HTTP/1.1 (以下、ブラウザとサーバに関する情報=HTTPヘッダ) … …
-
- レスポンス(サーバがブラウザに返す応答)
HTTP/1.1 200 OK (以下、HTTPヘッダ) … …
-
- URL
ブラウザは、URLを解釈してサーバにリクエストを送ります。
http://localhost:3000/members/show?id=123というURLなら、localhost(サーバ名)の3000番(ポート番号)に次のようなリクエストを送ります。
- URL
GET /members/show?id=123 HTTP/1.1 …
-
- メソッド::リクエストの種類
GET | 情報の要求 (WEBサーバからデータを取得) |
---|---|
POST | 情報の送信 (WEBサーバの状態を変更) |
HEAD | ヘッダ部分のみ要求 |
PUT | アップロード |
DELETE | リソースの削除 |
TRACE | リクエストをそのまま返送 |
OPTIONS | サーバが対応しているメソッドを取得 |
- ルーティング
リクエストされたURLから特定のコントローラ/アクションを選択すること。
特定のURLと特定のアクションを紐付ける場合、config\routes.rbで設定します。- URLのパス形式の設定
- コントローラ名・アクション名・パラメータを
http://localhost:3000/コントローラ名/アクション名/パラメータ というURLで表示させます。 - 複数のパラメータを使った形式も自由に追加できます。上から順に優先されます。
- コントローラ名・アクション名・パラメータを
- URLのパス形式の設定
map.connect ':controller/:action/:year/:month/:date' # URLを http://localhost:3000/コントローラ名/アクション名/年/月/日 という形式で表示(最優先) map.connect ':controller/:action/:id' # URLを http://localhost:3000/コントローラ名/アクション名/id という形式で表示
-
- URLとアクションの紐付け
- 第1引数には、特定のアクションを呼び出すURLのうち、http://localhost:3000/以下の部分を指定します。
- アクション名がindexの場合は、:action => 'index' を省略できます。コントローラ名は省略できません。
- URLとアクションの紐付け
map.connect '', :controller => 'ctr_name', :action => 'index' # http://localhost:3000/ というURLより、ctr_nameコントローラのindexアクションを実行 # public/index.rhtml が残っていると正しく動作しない(public/index.rhtml削除 ⇒ WEBrick再起動) map.connect 'hoge/fuga', :controller => 'piyo' # http://localhost:3000/hoge/fuga というURLより、piyoコントローラのindexアクションを実行
-
- publicフォルダ
publicフォルダには、ユーザに送信したいファイル(画像・スタイルシート・JavaScript等)を置くことができます。
Railsでは、リクエストされたパスとpublic内のファイルのパスが一致した場合、public内のファイルをコントローラ/アクションに優先して送信します。- 例: http://localhost:3000/stylesheet/css_name.cssというリクエストがあった場合、
public\stylesheet\css_name.cssを返送
- 例: http://localhost:3000/stylesheet/css_name.cssというリクエストがあった場合、
- publicフォルダ
コントローラとアクション
- コントローラ
class CtrNameController < ApplicationController before_filter :before_actions def index … end def action1 … end def action2 … end private def before_actions … end end
- 命名規約
コントローラ(クラス名) | HogeFugaController |
---|---|
コントローラ(ファイル名) | hoge_fuga_controller.rb |
テンプレート(親フォルダ名) | app/views/hoge_fuga |
ヘルパー(モジュール名) | HogeFugaHelper |
ヘルパー(ファイル名) | hoge_fuga_helper.rb |
レイアウトテンプレート(ファイル名) | hoge_fuga.rhtml |
機能テスト(ファイル名) | hoge_fuga_controller_test.rb |
- パラメータ
アクションの呼出と同時に指定できる変数。
params[:パラメータ名]の形で取得します。
パラメータはテンプレート内でも取得できます。
また、params[:controller]でコントローラ名を、params[:action]でアクション名を取得できます。
id = params[:id] name = params[:name]
- requestオブジェクト
リクエスト発信者の情報をもつオブジェクト。
主なメソッド | 機能 |
---|---|
request.remote_ip | リクエスト発信者のIPアドレスを取得 |
request.env['HTTP_USER_AGENT'] | リクエスト発信者のブラウザの種類を取得 |
request.get? | リクエストがGETメソッドかどうかを判別 |
request.post? | リクエストがPOSTメソッドかどうかを判別 |
- renderメソッド
特定のテンプレートをレンダリングさせるメソッド。
ハッシュの形で引数を指定します。
def action1 render :template => 'ctr_name/other_template' # 別のテンプレートにレンダリング # (indexアクションが実行されるとき、テンプレートはctr_name/other_template.rhtml) # :templateには、app\viewsを基点としたパスを指定 end def action2 render :action => 'action3' # 別のアクションのテンプレートにレンダリング # (action2アクションが実行されるとき、テンプレートはaction3.rhtml) # ただし、action3メソッドが呼び出されるわけではない end ^^^^^^^^ def action3 … end
render :file => "#{RAILS_ROOT}/public/404.rhtml", # publicフォルダ下のファイルをそのまま、 :status => '404 Not Found' # HTTPの404エラーとして表示
- redirect_toメソッド
HTTPのリダイレクションを実行するメソッド。
テンプレートのレンダリングとは異なり、新たにURLがリクエストされます。
引数にはリダイレクション先のアクションを指定するほか、コントローラを指定したり、パラメータを渡すこともできます。
def before_redirection redirect_to :action => 'after_redirection', :message => "リダイレクション" end def after_redirection @message = params[:message] #=> "リダイレクション" end
def before_redirection flash[:notice] = "移動しました" redirect_to :action => 'after_redirection' end def after_redirection @notice = flash[:notice] #=> "移動しました" # このアクションをリロードすると、@notice(flash[:notice])はnilになる end
-
- render/redirect_to の重複エラー
render/redirect_toメソッドは、1つのメソッドにつき1回しか実行できません。
もしメソッド内にrender/redirect_toメソッドを複数回記述する必要があるときは(なくても)、render/redirect_toメソッドの後にreturn(=その場でメソッドを終了)を記述しましょう。
- render/redirect_to の重複エラー
- フィルタ
- before_filter/after_filte
アクションの前/後に実行するprivateメソッドを宣言します。
原則として全アクションに適用されますが、:only/:exceptオプションを利用すれば、適用するアクションを特定することもできます。
- before_filter/after_filte
class CtrNameController < ApplicationController before_filter :before_actions, :only => [:action1, :action3] after_filter :after_actions, :except => :action1 # action1/action3の前にbefore_actionsが、 # action2/action3の後にafter_actionsが実行される def action1 … end def action2 … end def action3 … end private def before_actions … end def after_actions … end end
-
- around_filter
ここにprivateメソッドを宣言すると、全アクションにおいて、メソッドの途中でアクションが呼び出されるようになります。
オプションで適用するアクションを特定することはできません。
- around_filter
class CtrNameController < ApplicationController around_filter :around_actions def action1 … end def action2 … end def action3 … end private def around_actions … yield # ここで各アクションが呼び出される … end end
- verify
アクションの実行前に指定条件を満たしているか検証し、満たしていない場合は指定処理を実行します。
class CtrNameController < ApplicationController verify :only => [:action1, :action2], :params => :id, :redirect_to => {:action => :index} # action1/action2の実行前にparams[:id]があるか検証し、なければindexにリダイレクト def index … end def action1 … end def action2 … end def action3 … end end
-
- verifyのオプション
アクションの指定 | |
---|---|
:only => [:hoge, :fuga...] | hogeアクション,fugaアクションのみに適用 |
:except => [:hoge, :fuga...] | hogeアクション,fugaアクション以外に適用 |
条件 | |
:flash => :hoge | flash[:hoge]はあるか? |
:method => :get | HTTPのメソッドはGETか? |
:params => :hoge | params[:hoge]はあるか? |
:session => :hoge | session[:hoge]はあるか? |
:xhr => true/false | アクションはAJAXから呼ばれたか? |
条件を満たしていない場合の処理 | |
:add_flash => {:hoge => "ほげ"} | flash[:hoge]に"ほげ"を付与 |
:add_headers => {:hoge => "ほげ"} | HTTPヘッダのhogeフィールドに"ほげ"を付与 |
:redirect_to => {:action => hoge} | hogeアクションにリダイレクト |
:render => {:action => hoge} | hogeアクションのテンプレートにレンダリング |
- テンプレート
Railsのページデザインの基本は、コントローラで用意した変数をテンプレートに埋め込む方法です。
<% time = Time.now %> <p>現在、</p> <p><%= time -%> です。</p>
↓ブラウザ上の出力
現在、 Wed Aug 5 15:46:52 +0900 2009です。
-
- コントローラで変数を用意
# controller def index @time = Time.now.strftime("%H:%M") end
<p>現在、</p> <p><%= @time %>です。</p>
- 特殊文字の変換
HTMLコード上で意味をもつ記号(<, >, & 等)が変数に含まれていた場合、その変数をそのままテンプレートに埋め込むと、意図しないコードが実行されてしまう恐れがあり大変危険です。
railsのhメソッドは、これらの記号を変換(&lt;, &gt;, &amp; 等)してくれます。
# controller @danger = "<script>危険なコード</script>"
<%= h(@danger) %>
- ヘルパーメソッドの作成
ヘルパーには、テンプレートで利用するためのメソッドを自作することができます。
# helper def japanese_time(time) wday = ['日', '月', '火', '水', '木', '金', '土'] time.strftime('%Y/%m/%d<') + wday[time.wday] + time.strftime('> %H:%M:%S') end
# controller def index @time = Time.now end
<p>現在、</p> <p><%= japanese_time(@time) %>です。</p>
↓ブラウザ上の出力
現在、 2009/08/05<水> 15:46:52です。
-
- よく使われるヘルパーメソッド
- link_to::指定したアクションへのリンクタグを生成
- image_tag::指定した画像の表示タグを生成
- stylesheet_link_tag::指定したスタイルシートを適用
- よく使われるヘルパーメソッド
- レイアウトテンプレート
app\views\layoutsの下に作成します。
<!DOCTYPE …> <html> <head> <meta … /> <title>…</title> </head> <body> … <%= yield :layout %> <!-- アクション毎のテンプレート埋め込み --> … </body> </html>
-
- ctr_name.rhtml::CtrNameControllerで共通のレイアウトテンプレート
また、使用したいレイアウトテンプレートをコントローラ内で宣言することもできます。
- ctr_name.rhtml::CtrNameControllerで共通のレイアウトテンプレート
class CtrNameController < ApplicationController layout 'other_layout' # other_layout.rhtmlをレイアウトテンプレートとして使用 end
- 部分テンプレート
ファイル名は、_hoge.rhtmlのように_(アンダーバー)で始め、app\views\コントローラ名の下に作成します。
複数のコントローラで共有したい場合は、app\views\shared(あるいは任意のフォルダ名))の下に作成します。
部分テンプレートを呼び出したいビューの中で、次のように、ファイル名から_(アンダーバー)と拡張子を除いたものを指定します。
<%= render :partial => 'hoge' %> <%= render :partial => 'shared/hoge' %>
- スタイルシート
public\stylesheetsの下に作成します。
div#hoge a:link{ color: #000000 }
<div id="hoge"> <%= link_to "ほげへのリンク", :action => 'hoge' %> </div>
id属性"hoge"で囲まれた部分にCSSが適用されます。
また、子孫セレクタ(div#id属性名 要素名)を活用すれば、id属性に加えて要素ごとのデザインまで設定することができます。
上記の場合、ブラウザ上では、"ほげへのリンク"が黒色(#000000)で表示されます。