「コントローラー」とは?
ユーザーが、URLにアクセスした際に、リクエストが発行されますが、ユーザーからのリクエストを受け取り、モデルやビューへと渡す役割のプログラムのことです。
「コントローラー」を作成するには?
自動で生成できるコマンド(ジェネレータ)があります。
コマンド
1 |
rails g controller [コントローラー名] [アクション名] |
実行例
例えば、testというコントローラを作った場合は上記のような実行結果になります。
それぞれ、コマンド実行後は下記のフォルダやファイルが自動的に作成されています。
コントローラー
app/controllers/(アクション名)_controller.rb
デフォルトでは、下記のようなクラス(ApplicationControllerというクラスを継承したアクション名のクラス)が自動生成されています。
1 2 |
class TestController < ApplicationController end |
実際に、プログラムを書いていくのはこのファイルになります。
ビューフォルダ
app/views/(コントローラー名)にフォルダが出来ています。
この中に、アクションに対応するビューを配置していきます。
テストコード
実装したソースが正しく動作しているか、確認の自動化を行うものです。
test/controllers/(コントローラー名)_controller_test.rb
ヘルパーメソッド
ビューや、コントローラーから呼び出す共通処理をまとめたものです。
app/helpers/(コントローラー名)_helper.rbに格納されています。
アセット
Web関連のファイル(SCSS,CoffeeScript)のことです。
CoffeeScript
JavaScriptのコードを生成するためのプログラミング言語で、JavaScriptと言うよりはRubyに近い形で記述できるのが特徴です。
コントローラーを作成した際に、下記の場所に自動生成されます。
app/assets/javascripts/(コントローラー名).coffee
SCSS
CSSをよりプログラミング的にスタイルシートを記述するための言語でCSSに変換されます。
app/assets/stylesheets/(コントローラー名).scssに格納されています。
Ruby on Railsで、Hello World
それでは、実際にコントローラーにプログラムを書いてみましょう。
まずは、下記のように書きましょう。
1 2 3 4 5 |
class TestController < ApplicationController def index render plain: 'Hello world!' end end |
indexメソッド
コントローラーのアクションの一つです。「indexメソッド」というメソッドを記述して処理内容を記載します。
renderメソッド
Railsのコントローラーに備わっているメソッドで、クライアントへのレスポンス情報を定義します。
「plain:」
直後に指定した文字列をクライアントに返す指定です。
ルーティング情報の設定
ルーティングとは、特定のURLへのアクセスがあった場合に、どのアクションに振るかを定義する仕組みです。
Railsでは、config/routes.rbファイルにて記述をします。
1 2 3 4 |
Rails.application.routes.draw do # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html get '/test', to: 'test#index' end |
上記の「get '/test(アクション名)', to: 'test#index'」の部分が今回追加した箇所です。
項目 | 説明 |
---|---|
get | 「リクエストメソッド」です。今回はgetですが、フォームからの送信の場合にはpostを使う機会が多いでしょう。 |
/test | 「URLパターン」です。「リクエストURL」で、実際にユーザーが入力するURLを指定します。 |
to: 'test#index' | リクエストされた際に、対応するコントローラーとアクションを指定します。(コントローラー名#アクション名)、なお、これを省略することも可能でその場合は直接ビューファイルに飛ぶようになります。 |
ただ、このような定義はRailsが理想としているRestfulの思想には沿っていないです。実際の開発ではRestfulなルーティングになるよう修正した方が良いです。Restful APIに関しては下記で解説しています。
設定したルーティング情報を確認するには?
下記のコマンドを実行します。
1 |
rails routes |
対応するアクションの一覧を確認することができます。
URLにアクセスする。
「http://(該当サーバーのIPアドレス):3000/test(アクション名)」にアクセスすると下記のようにサイトが表示できています。
コントローラーから「ビュー」を呼び出す。
Railsは、MVCフレームワークなので、やはりビューは別途用意すべきです。
ビューを呼び出すには、コントローラーを下記のように書き換えます。
1 2 3 4 5 |
class TestController < ApplicationController def index render template: 'test/index' end end |
次に、「app/views/(アクション名)」の下にビューであるHTMLファイルを用意します。
app/views/test/index.html.erb
1 |
Hello World! |
HTMLの中に、出力したい文字列を記述します。
ビューファイルには、ERB(Embedded Ruby:HTMLにRubyコードを埋め込んだという意味)というファイル形式で、拡張子として「html.erb」というものをつけます。
Javaで言えば、「JSP」に相当する拡張子と捉えればよいでしょう。
URLにアクセスする。
「http://(該当サーバーのIPアドレス):3000/test(アクション名)」にアクセスすると下記のようにサイトが表示できています。
レンダリングのさせ方の種類
コントローラでのレンダリングのさせ方は下記の種類があります。
- redirect_toを使う
- renderメソッドを使う
- 何も指定しない。
redirect_to、renderメソッドを使う。
コントローラーのcreateアクションとビュー(new.html.erb)というようにコントローラーとビューの対応関係がない場合はrenderかredirect_toメソッドで遷移先のURLを指定してあげる必要があります。使い分けに関しては後述いたします。
何も指定しない
コントローラで何もレンダリング系のメソッドを指定しなかった場合は何も値を返さずにルーティングで対応しているビューに対してレンダリングさせることが可能です。インスタンス変数(@付きの変数名)をコントローラ内で定義している場合は呼ばれたビュー側でも使うことが可能です。ただし、例えばnewからcreateのアクションを呼んだときとかであれば対応するビュー(new.html.erb)が見つからないのでエラーになってしまいます。その場合はrenderを使うようにしましょう。
リダイレクトとレンダーの使い分け
Railsではリダイレクトは「redirect_toメソッド」で行いレンダーは「renderメソッド」で行います。
レンダー
特徴
コントローラーで作成した「インスタンス変数」はそのままViewに渡される。
用途
表示処理や、エラーが発生したとかただ表示させると言った処理の場合に使う。
リダイレクト
特徴
リダイレクトを行った場合再度ブラウザからリクエストを要する。
用途
登録、更新、削除等の何らかの処理が必要な場合はコントローラーでの処理が必要になるのでこちらを使う。
コントローラに記述する処理
- アクション群
- アクションの事前事後のフィルタ処理
- paramsに関する処理
- セッションに関する処理
- URL生成に関する処理
- モデルを利用する少量のコード
- メールやモデル以外のロジック
- ビューテンプレートのハンドリングやレスポンスの動的生成、リダイレクトの管理
モデルに記述するべき処理はモデルに寄せること
コントローラーはモデルとビューの中間的存在なので肥大化しやすいです。できるだけモデル側に処理を寄せるようにしましょう。
多少変わった形のparamsからの代入コード
モデル側でparamsの形を標準化したり、モデル側に適切な受け口(代入口)を作った上で一括代入で済ませる。(例えば、郵便番号が画面ではばらけているがモデルでは一つのカラムで片付ける場合はコントローラー側で処理せずに、モデル側で結合処理を行う。)
オブジェクトの内部状態を変更するコード(代入、処理呼び出し)
before_save等のコールバックを利用したり、統合的なメソッドを追加しましょう。例えば、人の年齢によって人の健康状態を変更するような処理であればモデル側にそのメソッドを記述しコントローラではそれを呼び出すだけにしましょう。
モデルの検索条件を作り込むコード
scopeを使います。
モデルを操作するために必要な情報を揃えるための準備処理
モデル操作に合わせて担当させるか必要情報を表すモデルを新設して揃える処理を担当させます。
ビジネスロジックをモデルに寄せる
下記のようなデメリットがあります。
- コントローラ側にビジネスロジックがあるとビューの数だけテストをしなければならなくなる。
コントローラーはあくまでレンダーやリダイレクト等の表示用の処理だけ記述し、計算処理や判定処理等の表示とは関係ないビジネスロジックの処理は記述しないようにしましょう。
アクションごとにモデルオブジェクトを作成する。
例えば、下記のように同じコントローラーの中で複数のアクション(indexやcreate)があった場合にそれぞれでモデルオブジェクトをnewします。
1 2 3 4 5 6 7 8 9 10 11 12 |
class XXXCntroller #一覧表示アクション def index @user = User.new end #登録アクション def create user = User.new(user_params) ‥ end end |
それぞれのアクションでnewする理由
Webアプリではブラウザからのリクエストの度にアクションが実行されて前のリクエストで処理された内容は次のパラメータでそのまま利用することはできません。RailsのPumaはマルチスレッドで処理するインスタンス変数にモデルオブジェクトを格納しているので他のリクエストでも一応アクセスすることは可能なのですが、そのためにはパラメータを渡したりもしくは、セッションやDBに保存すると言った手間が発生するので通常はこのように別々のアクションで別々のモデルオブジェクトを作るのが一般的です。
バリデーション時はモデルオブジェクトをインスタンス変数に格納する
例えば、登録画面とかでバリデーションを実施する前は必ず下記のようにモデルオブジェクトをインスタンス変数に格納するようにしましょう。
1 |
@task = モデル名.new(モデル名_params) |
理由
- 前回操作したままの値をそのままフォームに引き継いで表示することが可能にするため
- エラーになったオブジェクトのエラー内容を画面に表示することができるため。
もし、これができないとユーザーが再度一から入力し直しになってしまったり何をどう治して良いかわからなくなってしまうので非常にイライラすることになってしまうでしょう。
管理系機能を作る場合
管理者系の機能を作る場合は、「Admin::BaseController」という共通処理を実装した規定クラスを作利各管理系コントローラーに継承させるように作るのが一般的です。
登録、更新機能を作る場合
- strong parameterを使って特定のフィールドのみしかPOSTを許可しないような作りにします。(誤って意図しないパラメータが登録されたりしないように)
この記事へのコメントはありません。