**************
コントローラ
**************
====================
コントローラを作る
====================
学部の表示をするコントローラを作ってみる。
* ``rails generate scaffold`` がモデル・ビューと一緒に作ってくれるコントローラには、既に表示・編集・追加などの操作が入っている。
* ``rails generate controller`` は、必要なデータ操作を指定してコントローラを作る。
学部のデータは変更する必要がないので(学部の新設や廃止をするなら話は別だが)、学部の情報を表示する ``show`` という操作だけを作ることにする。 ::
% rails generate controller faculties show
* ``faculties`` がコントローラの名前。たまたまモデルと同じ名前(複数形)にしたが、モデルとは関係ない名前でもよい。
* ``show`` が操作の名前。操作が複数あるときは空白で区切って並べて書く。
これで ``app/controllers/faculties_controller.rb`` というファイルが出来て、 ``FacultiesController`` というクラスに ``show`` というメソッドが用意される。ただし中身は空。
それだけでなく、対応するビューのERBファイル ``app/views/faculties/show.html.erb`` も出来る。
=========================
Railsの処理の流れ大図解
=========================
.. image:: controller.png
コントローラが要求を受け付け、モデルとビューの間に立って処理を進める。要するに、モデルにもビューにも入らないところは全部コントローラに押し付けられる。
ルーティング
HTTPリクエストに対して、どのコントローラのどのメソッドが呼び出されるかという対応関係をルーティングと言う。
上の例だと、ブラウザで http://localhost:3000/faculties/show にアクセスすると、 ``faculties`` コントローラの ``show`` メソッドが呼び出される。
レンダリング
コントローラがビューを使ってレスポンスを作り出すことをレンダリングと言う。コントローラのメソッドの中で特に指定しなければ、コントローラ名とメソッド名から決まるERBファイルが自動的に使われる。
上の例だと、 ``faculties`` コントローラの ``show`` メソッドには何も書いていないので、 http://localhost:3000/faculties/show にアクセスすると、 ``app/views/faculties/show.html.erb`` を使ってレンダリングする。
==========================
コントローラの中身を書く
==========================
学部ごとに、学部名と学生リストを表示するようにしよう。
* コントローラはリクエストを解析してモデルから必要なデータを検索し、それをインスタンス変数に記憶する。
* ビューでは、そのインスタンス変数を使って表示を行う。
今は、ちょっと学部の指定は置いといて、常に総合政策学部のデータを取ってくることにする。 ``app/controllers/faculties_controller.rb`` は次のように書く。
.. code-block:: ruby
class FacultiesController < ApplicationController
def show
@faculty = Faculty.find(1)
end
end
これを表示するためのビュー ``app/views/faculties/show.html.erb`` は次のように書く。
.. code-block:: erb
Faculties#show
<%= @faculty.name %>
==================
パラメータの指定
==================
このままでは環境情報学部が表示できないので、リクエストのURLによって学部を指定するようにしよう。
* URLのクエリ文字列(最後に ``?hoge=xxx`` の形で付いているやつ)で指定された名前と値は、Rubyのハッシュに変換され、 ``params`` という変数に格納される。
例えば http://localhost:3000/faculties/show?id=2 でアクセスすると、 ``show`` メソッドの中では ``params[:id]`` の値が2になる。
``app/controllers/faculties_controller.rb`` は次のように書き直す。
.. code-block:: ruby
class FacultiesController < ApplicationController
def show
@faculty = Faculty.find(params[:id])
end
end
.. admonition:: 課題15
:class: exercise
学部の表示ページで、その学部に属する学生の番号と名前を表示するようにせよ。
1. コントローラで学生の配列を ``@students`` という変数に記憶する。
2. ビューでは ``<% @students.each do |s| %> ... <% end %>`` の形で各学生のデータを順次表示する。
提出は、 ``app/controllers/faculties_controller.rb`` と ``app/views/faculties/show.html.erb`` をアップロード。
:ref:`【解答例】 `
====================
ルーティングの指定
====================
* 参考資料: `Railsのルーティング - RailsGuides `_
ブラウザからのリクエストをどのコントローラのどのメソッドが引き受けるかは ``config/routes.rb`` で指定する。
* 基本的には、各行にHTTPリクエストのメソッド(HTTP Verb)とURLのパターンが書いてある。
* 上から順に見ていって最初にマッチしたところの指示に従う。
個別のルーティング
------------------
学部のコントローラーは ``rails generate controller`` で作ったので、 ``config/routes.rb`` には次の行が自動的に追加されている。
.. code-block:: ruby
get 'faculties/show'
* GETリクエストで http://localhost:3000/faculties/show というURLの時にマッチする。
* 本当は、この後に呼び出すべきコントローラとメソッドの指定を書くが、何も書かないとURLから勝手に判断する。この場合は ``FacultiesController`` の ``show`` メソッドが呼ばれる。
パラメータを含むルーティング
----------------------------
このルーティングでは、「どの学部か」という指定はURLの最後にクエリ文字列で ``?id=2`` とか書く必要がある。
* クエリ文字列は、長くなってうざい。
パス名の一部に直接パラメータを書くことができる。例えば、2番めの学部の情報を表示するには http://localhost:3000/faculties/2 と書ける。
.. code-block:: ruby
get 'faculties/:id', to: 'faculties#show'
* ルーティングの指定で、URLの中に ``:`` (コロン)で始まる名前を書くと、その部分がパラメータになる。
* ``:id`` に対応する部分が ``params[:id]`` に格納されてメソッドに渡される。
* URLが「コントローラ名/メソッド名」という形ではないので、コントローラ名とメソッド名の指定が必要。第二引数はハッシュで、キー ``to`` に対する値がコントローラ名とメソッド名を ``#`` でつないだ文字列。
リソースのルーティング
----------------------
学生のコントローラは ``rails generate scaffold`` で作った。
* ``app/controllers/student_controller.rb`` が出来ている。
* ``index``, ``create``, ``new``, ``edit``, ``show``, ``update``, ``destroy`` というメソッドが自動的に用意される。
このようにCRUD操作(作成、編集、表示、削除など)が一通りできるものをリソースと言う。
これに対するルーティングは、操作ごとに書くのは面倒なので ``config/routes.rb`` に ``resources :students`` と一行書けば自動的に行われる。
ルーティングの確認
------------------
URLとメソッドの対応が見たい場合は、次のコマンドを実行する。 ::
# rails routes -c students
Prefix Verb URI Pattern Controller#Action
students GET /students(.:format) students#index
POST /students(.:format) students#create
new_student GET /students/new(.:format) students#new
edit_student GET /students/:id/edit(.:format) students#edit
student GET /students/:id(.:format) students#show
PATCH /students/:id(.:format) students#update
PUT /students/:id(.:format) students#update
DELETE /students/:id(.:format) students#destroy
* ``-c`` オプションでコントローラを指定する。指定しないと全部出てくるが、大変見づらい。
* Prefix はヘルパーメソッドの名前などに使われるもの。
* Verb はHTTPメソッドのこと。普通はGET、フォーム送信の時はPOST。それ以外は特別に指定しないと使われない。
* URI Pattern はURLのアプリケーション名より後の部分。 ``(.:format)`` はとりあえず無視してよい。
* Controller#Action はコントローラ名とメソッド名を ``#`` でつなげたもの。
操作を限定したリソースルーティング
----------------------------------
学部は個別ルーティングになっているが、リソースにするとヘルパーメソッド( ``faculty_path`` など)が使えたりして便利。しかし、 ``index`` や ``create`` といった操作は用意していないので、使える操作を限定しないといけない。
``config/routes.rb`` の ``get 'faculties/:id'`` のところを次のように書き換える。
.. code-block:: ruby
resources :faculties, only: [ :show ]
* ``only:`` の後に、このリソースで使える操作( ``faculties`` コントローラのメソッド名)をシンボルの配列で書く。
* 操作は一般に複数個あるので、1個だけでも配列で指定する。
==============
今日のまとめ
==============
.. admonition:: 課題16
:class: exercise
前々回の課題で作った科目のモデル ``Course`` について、コントローラとビューを作成せよ。ただし、URLと操作は次のようにする。
* http://localhost:3000/courses で科目一覧と各科目の詳細ページへのリンクを表示
* http://localhost:3000/courses/1 で1番の科目の詳細を表示(科目名と単位数。必修科目の場合はその旨を表示。)
提出は、科目のコントローラ、科目一覧のERBファイル、科目詳細のERBファイル、 ``config/routes.rb`` をアップロード。
:ref:`【解答例】 `
.. admonition:: 課題17
:class: exercise
最終課題のアプリケーションについて、モデルとビューがどうなるか考えよ。
1. 表示したい画面の構成を考え、絵を描いてみよ。
2. データベースに記録するデータには何があるか、表の項目を列挙してみよ。
:ref:`【解答例】 `
`ここまでのソースコードはこちら `_
`課題16実行後 `_