Hit the books!!

プログラミング学習記録

ストロングパラメータとレンダリングとリダイレクトの基本

今回はコントローラーの話。

<参考>

コントローラーが扱うパラメータ

コントローラーのactionで参照できるパラメータには次のようなものがある。

フォームパラメータ/POSTパラメータ(request_parameters)

画面の入力フォーム(form_withヘルパーを通して生成されるformタグ)から送信される入力データ。

ルートパラメータ/パスパラメータ(path_parameters)

URIの一部としてルートに組み込まれるパラメータ。例えば、リソースを特定する「:id」パラメータが該当する。

クエリパラメータ/GETパラメータ(query_parameters)

URIのうち「?」以降で指定される問い合わせなどに使用されるパラメータ。例えば「http://example.com/users/search?age=25%area=10」のように、パラメータ=値という形式でURIパスの?以降に付加し、複数の場合は=でつなぐ。

パラメータの参照

パラメータの値を参照するにはparamsインスタンスを使用する。

params値の取得例は以下の通り。

パラメータの種類 データ受け渡し形式 params値の取得例
フォームパラメータ フォームデータ params[:book]/params[:book][:title]
ルートパラメータ /users/:id params[:id]
クエリパラメータ /users?lang=jp&currency=jpy params[:lang]/params[:currency]

ストロングパラメータ

ストロングパラメータとは、マスアサインメントというセキュリティの脆弱性を回避するための手段である。マスアサインメントとは、クライアントから受け取ったparamsハッシュのフォームパラメータをそのまま一括指定して受け取ったデータのモデルオブジェクトを自動生成する機能である。便利だがクライアントから送られてきたデータに不正に組み込まれたパラメータ属性があると、バリデーションの機能をすり抜けてそのまま取り込まれてしまう可能性がある。

ストロングパラメータの実装例

ユーザ情報(Userモデル)の新規登録の場合を考える。

受信した新規ユーザの入力データはparams[:user]で取得でき、このparamsインスタンスの中のハッシュ化された入力データの値を使用して、Userモデルの新規登録処理を行うことができる。

User.new(params[:user])

Railsではマスアサインメントを防ぐためデータの保存処理などを行う前にパラメータに対して許可処理を行う必要がある。上記のままだと"禁止された属性"という例外エラー「ActiveModel::ForbiddenAttributesError」が発生してしまうため、ストロングパラメータ化が必要になる。

ストロングパラメータ化は、paramsハッシュのrequireメソッドとpermitメソッドを組み合わせて行う。

  • requireメソッド:対象パラメータグループの要求
    • 書式:require(対象のパラメータのグループに相当するハッシュキー)
  • permitメソッド:個々のパラメータの許可を与えるホワイトリストの指定

Userモデルに対する実装例↓

class UsersController < ApplicationController
  ...(省略)
  def create
    @user = User.new(user_params)
    ...(省略)
  end
  
  def update
    respond_to do |format|
      if @user.update(user_params)
      ...(省略)
      end
    end
  end
  
  private
    def user_params
      params.require(:user).permit(:name, :address)
    end
end

params.require(:user).permit(:name, :address)の内容は、

  • リクエストに:userというkeyが必要であること
  • userの中で受けてもいいのは:name, :addressの2つのkeyのみ

という意味である。

なお、ストロングパラメータはあくまでマスアサインメントを回避するためのものであって、入力データの値そのものに組み込まれるSQLインジェクションを回避するものではない。

renderメソッド

レンダリングとは、コントローラーのアクションがrenderメソッドを使用してビューの出力を指示する作業。

renderメソッドは、指定されたルールに基づいて対応するビューテンプレートを呼び出し、それをもとにアクション内で指示されたインスタンス変数の値などを使ってHTMLを生成する。コントローラーは、この結果をHTTPレスポンスのデータとしてクライアントへ転送し、クライアントのブラウザに画面を表示させる。

1回のアクション処理の実行において、renderメソッドは1回だけ実行される。複数回実行させようとすると例外が発生する。

暗黙的なrenderメソッドの実行

次の4つの条件に該当する場合は、renderメソッドを指示しなくてもRailsの規約に従って暗黙的にrenderメソッドを動作させることができる。

  1. ルートで呼び出されたアクションがことローラー内にない
  2. ルートで呼び出されたアクション内にrenderメソッドがない(ただし、redirect_toメソッドがある場合は除く)
  3. ルートで呼び出されたアクション内のrenderメソッドにビュー名を指定する引数がない
  4. ルートで呼び出されたアクション内のrenderメソッドのビュー名がアクション名と同じ

これらの場合、Railsは指示されたアクション名に相当するビューテンプレート(erbファイル)を探し出しrenderメソッドを実行する。

renderメソッドのオプション

renderメソッドの主なオプションは以下の通り。

オプション 役割
:action(省略可) 同じコントローラー内の他のアクションのテンプレートを出力する場合に指定する render action: :indexまたはrender :index
:template(省略可) 異なるコントローラーのディレクトリ配下のテンプレートを指定して出力する render template: 'users/index'またはrender 'users/index'

ビューテンプレートを使用しないレンダリング

ビューデザインに基づくテンプレートを必要とせず、簡単に結果を送信したい場合や動的に構成したビューを出力したい場合は、コントローラーからビューテンプレートを介さずに、直接文字列形式でHTMLビューを構成してレンダリングすることができる。

書式:render オプション: '出力対象の内容'

オプションとして、次の3種類から選ぶことができるが、どのオプションを使うかによってクライアントに送信されるHTMLデータの内容が異なるため注意が必要。

  • plainオプション
  • htmlオプション
  • inlineオプション

redirect_toメソッド

redirect_toメソッドは、コントローラーのアクション内で使用する、アクション実行後に他のルートへリダイレクト(宛先変更HTTPリクエスト)を行うメソッド。

通常はアクションの終了時にrenderメソッドでHTMLビューを生成してHTTPレスポンスを送信するが、アクション終了後に他のアクションを実行したい場合や他のサイトへ接続したい場合にredirect_toメソッドを使用する。リダイレクト先のURIは指定するオプションによって自動生成することができる。

リダイレクトの例

Libraryアプリケーションを簡略化した例をみる。

class BooksController < ApplicationController
  ...(省略)
  def create
    @books = Book.new(book_params)
    if @book.save
      redirect_to @book, notice: 'Book was successfully created.'
    else
      render :new
    end
  end
  ...(省略)
end

このリダイレクトで指定している宛先URIはルーティングヘルパーの簡略形の@bookである。Bookモデルの登録が成功すると、「http://~/books/@bookのid値」に基づいてルーティング「book GET /books/:id(.:format) books#show」によってルートが割り振られる。結果、Booksコントローラーのshowアクションが実行される。

次のように、引数に外部のURLを渡すことでリダイレクトすることもできる。

redirect_to 'http://www.example.com'

redirect_toメソッドのオプション

主なオプションは次の通り。

  • notice: メッセージ

    • リダイレクト先に通知メッセージを表示させる。noticeの内容を表示させるためには、使用するビューテンプレートに<%= notice %>のようにして埋め込む。
  • alert: メッセージ

    • リダイレクト先に警告メッセージを表示させたいときに使用する。alertの内容を表示させるためには<%= alert %>のようにして埋め込む。
  • flash: {パラメータ: 値}

    • 任意のハッシュパラメータを使ってリダイレクト先へ値を渡す。例えばremarkを使用してflash: {remark: 'この処理には注意が必要です'}というようにリダイレクト先に値を通知する。リダイレクト先では、<%= flasho[:remark] %>のようにして利用する。