『Ruby on Rails5 アプリケーションプログラミング』学習日誌 7
- 前書き
- ページ範囲
- スキーマファイルの実行について
- コントローラ
- ストロングパラメーター
- リクエストヘッダとサーバ環境変数
- アクションでの処理結果の出力について
- 状態管理
- send_file
- loggerオブジェクト
- json.jbuilderファイル
- Action Pack Variants
前書き
今日も第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
クッキーとはクライアント側に保持される簡易的なテクストファイルのことである。原則ではサーバがクライアントにデータを書き込むことは許していない中でクッキーは唯一の例外。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で追加することができる。