『Ruby on Rails5 アプリケーションプログラミング』学習日誌 7

前書き

今日も第6章コントローラについて学習します。あと、ここに書いてあることは単なる学習記録なので事実とは関係がない場合があります。ご了承ください。

ページ範囲

p.312-400

スキーマファイルの実行について

db/schema.rbにはdbの最新のスキーマ情報が記載されている。これはマイグレーションファイルの実行が記録されているからである。

rails db:schema:load

でdbに内容を反映することができる。

コントローラ

コントローラの基本

コントローラの役割は大きく言ってリクエスト情報の取得とレスポンスの生成にある。リクエスト情報とはクライアントから送信された値のこと。コントローラで定義されている各メソッドのことをアクションと呼ぶ。

各種リクエスト情報
種類 概要
ポストデータ httpメソッドがpostのformから受け取った情報。
クエリ情報 urlの?以降に「キー=値&…」で受け取る情報。
ルートパラメータ /1などルートで渡された情報。

これらを1つにまとめて

params[:パラメータ名]

という形でアクセスできるようになっている。ルートパラメータの場合はparams[:id]でアクセスできる。

ストロングパラメーター

例えば下記のようにフィルターとしてコントローラーごとにストロングパラメータをまとめて定義しておくと便利。(scaffoldでは自動生成される)

def user_params
      params.require(:user).permit(:username, :password_digest, :email, :dm, :roles, :reviews_count, :agreement)
    end

でformの内容が受け取られることになる。ここで使われているメソッドのrequireとpermitはいわゆるストロングパラメータと呼ばれるものでformからリクエストを投げたときの返り値のうち必要なものだけを受け取るための仕組みである。requireなどの制限がない場合リクエストの返り値はモデルの全てのパラメータやコントローラ名、アクション名なども含めた情報が帰ってきているので予期せぬ値が入り込まないように、取得する値を限定する意味がある。

リクエストヘッダとサーバ環境変数

ブラウザからサーバに送られる不可視の情報のことをヘッダー情報と呼ぶ(逆方向ならレスポンスヘッダ)。対応している言語やブラウザの種類のことなど。リクエスト時に送信されるヘッダのことをリクエストヘッダと呼ぶ。

request.headers[パラメータ]

で取得できる。またサーバ環境変数も取得することができ、例えば

request.fullpath

などがある。これはその処理のリクエストurlが得られる。

アクションでの処理結果の出力について

アクションでの処理結果の出力のためのメソッド

メソッド 概要
render テンプレートの呼び出しなど、汎用的な結果出力の手段
redirect_to 指定されたアドレスに処理を移動
send_file 指定されたファイルに出力
send_data してされたバイナリデータを出力
head 応答ヘッダーのみを出力

renderメソッド

上記のメソッドの中で最も基本的なもの。出力について明示的な指定がない場合は暗黙的にrenderが呼び出されて、受け取ったリクエストの内容から推測される。テンプレートを呼び出す場合が多いが、json形式のデータを出力したりもできる。

redirect_toメソッド

引数のurlに処理を移動する。urlは文字列かハッシュ形式で渡すことができる(url_forメソッドと同様)。

send_fileメソッドとsend_dataメソッド

これらは指定されたパスにあるファイルやバイナリデータを読み込み、その内容をブラウザに送信する。

状態管理

状態管理とは複数のアクション間で情報を維持するための仕組みのこと。httpは本来ブラウザからのリクエストに対してサーバがレスポンスを返すだけのシンプルな仕組みになっている。そのため、複数回に渡るアクションは連続性を持たず、サーバはそれぞれを独立した別のクライアントとのやりとりだと認識している。しかし、これはそれぞれのユーザに合わせたサービスを提供したwebアプリにとっては致命的な制約になってしまう。なので何らかの方法で情報を維持するための仕組みが必要でそのことを状態管理と呼ぶ。下記のようにいくつかの方法がある。

状態管理の方法

機能 概要
クッキー ブラウザ側に持たせるテキスト情報
セッション クッキー、キャッシュ、dbなどに状態情報を保存する仕組み
フラッシュ 現在と次のリクエストでのみ維持できる特殊なセッション情報

クッキーとはクライアント側に保持される簡易的なテクストファイルのことである。原則ではサーバがクライアントにデータを書き込むことは許していない中でクッキーは唯一の例外。cookieはレスポンスヘッダ経由でブラウザ等に発行される。また同一クライアントの2回目以降のアプリ訪問時にリクエストヘッダ経由でサーバに送信される。それによってユーザの状態を判断し、それに基づき最適化されたリアクションをサーバ側から返すことができる。リクエストヘッダやレスポンスヘッダなどのヘッダ情報とはブラウザ⇄サーバ間で送信されるhttpメッセージに伴う不可視の情報のこと。cookiesメソッドはオプション名:値のハッシュ形式で設定することができる。

オプション名 概要 値の例
value クッキーの値 -------
expires クッキーの寿命 3.hours.from_now
domain クッキーが有効なドメイン yshrfmru.com
path クッキーが有効なパス /test/
secure trueの場合、暗号化通信でのみクッキーを送信 true
httponly httpクッキーを有効にするかどうか true

上の二つは必須のオプション。expiresを設定しない場合クッキーの寿命はブラウザを閉じるまでとなる。httponlyを有効にすることによって、jsからのクッキーアクセスができなくなり、xss攻撃によるクッキー盗聴を防ぐことができる。

session/flash

セッションとフラッシュについてはすでに取り上げたので補足のみ。sessionではその情報の保存先をクライアントサイド(クッキー)かサーバサイド(DB、キャッシュ)から選ぶことができる。ただし、セッションのidはクッキーに持たせることで、ユーザを区別する。

send_file

指定されたパスのファイルを読み込んで、その内容をクライアントに送信する。設定できるオプションがいくつかある。

オプション 概要 デフォルト
filename ダウンロード時に使用するファイル名 元のファイル名
type コンテンツタイプ(モデルに対してはctypeなどで指定可) application/octet-steam
disposition ファイルをブラウザインラインで表示するか(:inline)ダウンロードするか (:attachment) :attachiment
status ステータス 200 ok
url_based_filename ダウンロード時のファイル名をurlをもとに生成するかどうか false

loggerオブジェクト

アクションメソッドなどでの途中経過を確認するためログを標準出力やログファイルに出力するために利用できる。表の上の方ほど優先順位が高い。

メソッド 概要
unknown(msg) 不明なエラー
fatal(msg) 致命的なエラー
error(msg) エラー
warn(msg) 警告
info(msg) 情報
debug(msg) デバッグ情報

json.jbuilderファイル

scaffold を利用した場合はviewフォルダに自動的に生成される。jsonデータを生成するためのテンプレート。erbとは違い、rubyスクリプトがそのまま記述されている。

json.array! @books, partial: 'books/book', as: :book

json.array!メソッドでは第一引数にレコードのインスタンスをとり、partial:オプションで部分テンプレートのurlをとる。ここで呼び出す部分テンプレートはjson.jbuilder拡張子のついたjsonデータ用のテンプレートである。as:オプションで指定した値をパラメータとして、部分テンプレートから@booksのjsonにアクセスすることができる。

### フィルター

before_action 、 after_action とaround_action でフィルターを設定することができる。それらの引数になるmethodがフィルターとなる。オプションでonlyで指定すると指定したメソッドのみにフィルターをかけられる。また、exceptで指定するとフィルターをかけないメソッドを指定することができる。これらのオプションを指定しない場合は全てのメソッドにフィルターが適用される。なお、only/exceptはなるべく使わないようにコントローラの設計をすることが大切である。アクションの実行のフローが複雑になるとコードの可読性が損なわれるためである。

フィルターは予期せぬ動作を防ぐために、privateメソッドとして定義した方がいい。around_actionで指定するフィルターにはyieldを定義することによって、フィルターの対象となるメソッドの実行するタイミングを明示する必要がある。また、フィルターによって条件分岐を行い、renderメソッドを通すことによって、アクションをスキップすることもできる。

フィルターの継承

フィルターはコントローラをまたいで適用することもできる。継承関係にあるコントローラではフィルターも継承することができる。例えばApplication Controllerには全てのアクションに共通するフィルターを儲けることが出来る。実行される順は継承の親になるコントローラほど早くなる。

skip_XXXX_actionメソッド

XXXXの部分はbefore、after、aroundなどが入るが、これを宣言することで引数のフィルターをスキップすることが出来る。ただしスキップできるのは基底コントローラで定められたフィルターのみである。

authenticate_or_request_with_http_basic

authenticate_or_request_with_http_basicメソッドはそれ単体で認証の要求から入力されたパスワードの判定までを行う。ブロックにはnameとパスワードを渡してブロック内でその妥当性を判定するためのロジックを記述することが出来る。

Action Pack Variants

レスポンシブデザインを使わずにviewをデバイスごとに合わせて表示する方法のこと。

ruby request.variant = :mobile

のようにrequestオブジェクトのvariantプロパティにデバイスを指定しておくことによって適用されるviewが自動的に選択される。これはヘッダ情報から条件分岐すると良い。上記の例で言えばindex.html+mobile.erbが描画されることになる。指定がない場合はindex.html.erbが描画される。ちなみにrequestオブジェクトとはクライアントブラウザから送られてくる様々なリクエスト情報を含むオブジェクト。

requestのプロパティ 返り値
host リクエストで使用されるホスト名
domain(n=2) ホスト名の右から数えてn番目のセグメント
method リクエストで使用されたhttpメソッド
get?など httpメソッドが指定したものだった場合にtrueを返す
headers リクエストに付随するヘッダ情報
port リクエストに使用されたポート番号
protocol http://などプロトコル名に://を付けたもの
query_string urlの一部で使用されているクエリ文字(?以降)
remote_ip クライアントのipアドレス
url リクエストで使用されるurl全体

add_flash_type メソッド

フラッシュではnoticeキーやalertキーが用意されている。これらはredirect_toメソッドの引数として渡したり、view側でローカル変数のように使用したりすることが出来る。このようなキーをadd_flash_typeで追加することができる。