Rails開発を面白くするアクションコントローラーの5大機能とルーティングの基本:開発現場でちゃんと使えるRails 4入門(7)(2/3 ページ)
エンタープライズ領域での採用も増えてきたRuby on Railsを使ってWebアプリケーションを作るための入門連載。最新版の4に対応しています。今回は、MVCモデルにおける「C」の部分をつかさどるActionControllerの主な機能とアクションとパスの対応を定義するルーティングなどについて解説します。
Rails 4から導入された「Strong Parameter」
Rails 4から導入されたStrong Parameterはリクエストに含まれていてもよいパラメーターをコントローラーで指定する機能です。悪意のあるユーザーがフォームに存在していない属性の入力欄を追加してPOSTリクエストしてきても、その属性を弾くことができます。
Strong Parameterの挙動を理解するために前節のPOSTデータパラメーターを使って実験してみましょう。
まず「new」メソッドに「params」が持つパラメーターをHashオブジェクトのように渡すRails 4より前のやり方を試してみます。
params[:book] => { "title" => "新しい本", "author" => "新しい作者" } Book.new(params[:book]) => ActiveModel::ForbiddenAttributesError: ActiveModel::ForbiddenAttributesError
このように「params」をHashオブジェクトと同じようにモデルの複数属性の初期化に使うとエラーが発生します。
それでは、「params」とは何でしょうか。
params[:book].class => ActionController::Parameters < ActiveSupport::HashWithIndifferentAccess params[:book].class.superclass => ActiveSupport::HashWithIndifferentAccess < Hash
「params」はHashクラスを継承していますが、Hashではありません。これを用いて複数属性の初期化に用いるには次のようにメソッドチェインの返り値を使います。
Book.new(params.require(:book).permit(:title)) => #<Book:0x007fc8d8781088> => Unpermitted parameters: author
「permit」メソッドの引数には初期化する複数の属性名を渡せます。そこに含まれていない属性がparamsに含まれていると上のようなログが出力されます。
Book.new(params.require(:book).permit(:title, :author)) => #<Book:0x007fc8d8781088>
上記のように、作成・更新に使いたいパラメーターだけをpermitし、paramsからBookクラスのインスタンスを生成します。
【2】リクエスト間でデータを保存する「クッキーとセッション」
クッキーとセッションはリクエストの間でデータを保存する方法で、ログイン状態の管理などに使われます。
クッキー
クッキーはユーザー側で一時的に保存されるデータです。セッションを使う上でもセッションIDをユーザー側で保存するために使われます。クッキーを保存するには次のように操作します。
# クッキーの値だけを保存(この値はブラウザーを閉じると消去されます) cookies[:condition] = ‘good’ # オプションを付けて保存 cookies[:condition] = { value: ‘soso’, # クッキーの値 expires: 1.day.from_now # クッキーの有効期限 }
またクッキーを読み出すときはハッシュと同じようにします。
cookies[:condition] # => ‘soso’ # 設定されていなければ cookies[:hoge] # => nil
セッション
セッション、データをサーバーで保持し、そのデータを取り出すセッションIDをクッキーとしてユーザー側で保存します。セッションは次のように保存します。
session[:user_id] = @user.id
取り出すときはクッキーと同様です。
session[:user_id] # => 1
【3】簡単なメッセージを表示する「フラッシュ」
フラッシュはデータの保存成功などの簡単なメッセージを表示する仕組みです。フラッシュはセッションに保存され、リダイレクトした先でも設定したメッセージを表示できます。
def index flash[:notice] = “現在時刻:#{Time.now}” end
表示するにはビューで次のようにして設定したキーで呼び出します。
<div id=”flash”> <%= flash[:notice] %> </div>
フラッシュはアクションが終了する際に削除されるため、以降のリクエストでは表示されません。
【4】アクションを実行する前後に処理を挟む「フィルター」
「ActionController」には、アクションを実行する前後に前処理や後処理を挟むフィルターが用意されています。アクションの前に実行される「before_action」フィルター、後に実行される「after_action」フィルター、アクションの前後にまたがって実行される「around_filter」フィルターがあります。
「scaffold」で作成したコントローラーでは次のようなフィルターが実装されています。
class BooksController < ApplicationController before_action :set_book, only: [:show, :edit, :update, :destroy] (略) private # Use callbacks to share common setup or constraints between actions. def set_book @book = Book.find(params[:id]) end
このように「before_action」の宣言にフィルターの処理を行うメソッド名を渡して使用できます。またメソッド名ではなくフィルター処理のブロックや、フィルターオブジェクトを渡すこともできます。
フィルターオブジェクトは「before_action」に渡す場合であれば「before」メソッドか「filter」メソッド、「after_action」に渡す場合であれば「after」メソッドか「filter」メソッドにフィルターの処理を実装しておく必要があります。
「around_filter」に渡す場合は「filter」メソッドまたは「around」メソッドにアクションの処理を埋め込む「yield」を含めて実装します。
class TransactionWrap def filter(controller, &action) ActiveRecord::Base.transaction do yield raise ActiveRecord::Rollback if @book.errors.present? end end end class BooksController < ApplicationController around_action TransactionWrap.new, only: [:create, :update] (以下略)
また、フィルターの宣言時に「only」オプションでフィルターを実行するアクションを指定でき、「except」オプションで全てのアクションからフィルターを実行しないアクションを指定することもできます。
Copyright © ITmedia, Inc. All Rights Reserved.