ESLint + Airbnb JavaScript Style Guide でエラー Configuration for rule "jsx-a11y/anchor-has-content" is invalid
現在の職場で、SPA実装のためにJS記述量が増えてきてESLintを導入しました。
Reactも使っているので、Airbnb JavaScript Style Guideを使いました。
そこで遭遇したエラーの話です。
ESLintインストール
Web上に情報はたくさんあると思います。以下のあたり参照してもらえれば。
ESLint をグローバルにインストールせずに使う - Qiita
私はプロジェクトローカルにインストールしました。
npm install --save-dev eslint
eslint --initでairbnbスタイルガイド適用した場合、エラーになる
ESLintで使う設定ファイルが.eslintrc.json
で、これはeslint --init
コマンドで作成することもできます。
コマンド実行して、ターミナルに表示される質問に対し希望の回答を選択していけば、.eslintrc.json
が作成されます。
私は以下のように答えました。
$ eslint --init ? How would you like to configure ESLint? Use a popular style guide ? Which style guide do you want to follow? Airbnb ? Do you use React? Yes ? What format do you want your config file to be in? JSON
以下のような.eslintrc.json
が作成されました。
{ "extends": "airbnb", "plugins": [ "react", "jsx-a11y", "import" ] }
ここでeslintを実行してみるとエラーに遭遇しました。
$ eslint test.js /...path_to_your_project.../node_modules/eslint-config-airbnb/rules/react-a11y.js: Configuration for rule "jsx-a11y/anchor-has-content" is invalid: Value "" is the wrong type.
the airbnb config requires 2.x of eslint-plugin-jsx-a11y (NOT 3.x)
で報告されている現象でした。
eslint --init
でairbnbスタイルを適用した場合、
依存関係でインストールされるプラグインeslint-plugin-jsx-a11y
のバージョンが正しくならないようです。
GitHub - evcohen/eslint-plugin-jsx-a11y: Static AST checker for a11y rules on JSX elements.
ljharbさんのコメントが参考になります。
https://github.com/eslint/eslint/issues/7338#issuecomment-252785808
https://github.com/airbnb/javascript/issues/1172#issuecomment-259643396
https://github.com/evcohen/eslint-plugin-jsx-a11y/issues/119#issuecomment-259574657
airbnb style guideを適用するには、2.x系が必要なのに、eslint --init
で適用した場合 3.x系が入ってしまい動かないということらしいです。
https://github.com/airbnb/javascript/tree/master/packages/eslint-config-airbnb
の記述通り、以下のように実行すれば私の環境では解決しました。
Linux/OSX users can simply run ( export PKG=eslint-config-airbnb; npm info "$PKG@latest" peerDependencies --json | command sed 's/[\{\},]//g ; s/: /@/g' | xargs npm install --save-dev "$PKG@latest" )
2.x系がインストールされ、ESLint + Airbnb JavaScript Style Guideで実行できるようになりました。
minitest-reporters : rake test の実行結果を色付きで出力する
minitest-reporters
Rails4標準のminitestのテストをrake test(rake のみでも同じ)
で動かしても出力結果に色は付かない。
やはり、成功は緑、失敗は赤、スキップ等は黄色で表示したい時、
minitest-reporters というgemを使えば良い。
Gemfileに追記してインストールしたら、Usage の通り、
test_helper.rb
に、
require "minitest/reporters" Minitest::Reporters.use!
と記述すれば良い。
参考
http://railstutorial.jp/chapters/static_pages?version=4.2#sec-minitest_reporters
provide() : Template間で値を渡すヘルパーメソッド
ドキュメントは以下
http://api.rubyonrails.org/classes/ActionView/Helpers/CaptureHelper.html#method-i-provide
よくある使い方の一つは、各アクションのViewで、
<% provide(:title, "Home") %>
として、 シンボル :title
に 文字列 "Home"
を関連付ける。
レイアウトViewで、
<%= yield(:title) %>
のように参照する、という使い方だ。
Railsでの開発経験者であれば、この時点でcontent_forの使用を検討すると思いますが、残念ながらAsset Pipelineと併用すると正常に動作しないことがあります。provide関数はcontent_forの代替です。
参考
http://railstutorial.jp/chapters/static_pages?version=4.2#sec-layouts_and_embedded_ruby
Railsで rails generate / rake db:migrate を「元に戻す」方法
destroy: rails generate を元に戻す
rails generate(省略形 rails g)
でcontrollerやmodelを生成する場合、複数のファイルが一括で生成され、ルーティングの config/routes.rb も修正されるので、これを取り消すためのコマンドがrails destroy
である。
例えば、
$ rails generate controller StaticPages home help
として実行した結果を取り消すなら
$ rails destroy controller StaticPages home help
とコマンドを打つ。
rollback: rake db:migrate を元に戻す
マイグレーションのコマンド rake db:migrate
を取り消すためのコマンドが rake db:rollback
だ。このコマンドで一つ前の状態に戻すことができる。
マイグレーションは逐次的に実行され、各マイグレーションに対しバージョン番号が付与されているので、この番号を指定することで指定したバージョンの状態に戻すことができる。
最初の状態に戻す場合は、以下コマンドになる。
$ rake db:migrate VERSION=0
参考
Railsチュートリアルの「コラム3.1 元に戻す方法」より
http://railstutorial.jp/chapters/static_pages?version=4.2#aside-undoing_things
PHPでセッション管理のメモ
以下、PHPのセッション管理についての簡単なメモだ。
セッション管理とクッキー
セッション管理
HTTP自体はステートレスなプロトコルでサーバ側で状態を保持しない。 しかし、ログイン後の認証状態、ECサイトのショッピングカートなど、アプリケーションによっては状態を保持しておく必要がある。 このように、ユーザ毎にサーバ側での状態を覚えておくことをセッション管理という。
クッキー
セッション管理をHTTPで実現するための仕組みがクッキー(cookie)だ。
サーバ側からの指示に従い、ブラウザは「名前=変数」の組を記憶する。
セッション開始
以下、動作確認しながら説明する。
次のファイルは、session_start() 関数でセッションを開始するサンプルである。
sessiontest1.php
<?php session_start(); ?> <html> <head><title>PHP TEST</title></head> <body> <?php if (!isset($_COOKIE["PHPSESSID"])){ print('初回の訪問です。セッションを開始します。'); }else{ print('セッションは開始しています。<br>'); print('セッションIDは '.$_COOKIE["PHPSESSID"].' です。'); } ?> </body> </html>
初めてこのファイルにHTTP GETでアクセスした場合、 レスポンスにはSet-Cookieヘッダがあり、 この情報をブラウザに記憶するように指示している。
ちなみにChromeの場合はフォームに chrome://settings/cookies
と入力すれば
記憶しているCookieを確認することができる。
そして、再度このページにHTTP GETでアクセスする時は、 リクエストのCookieヘッダに記憶した情報が付与されている。
ここでやり取りされていたPHPSESSID=****
という情報はセッションIDといい、
サーバに保存されている全てのユーザのセッション情報の中で、ユーザを特定するためのIDである。
なお、セキュリティの観点から、認証(ログイン)後、セッションIDを更新した方がよい。
ちなみに、PHPSESSID
はセッション名といい、phpの場合はphp.ini
ファイルでデフォルト値として設定されており、
変更することも可能だ。
そして、この値は session_name() 関数で取得できる。
つまり、クッキーに保存されたセッションIDは$_COOKIE[session_name()]
と書いても取得できる。
セッションの管理と終了
サーバ側で管理したいセッション情報は、$_SESSION
の連想配列を使って管理する。
このセッション情報はWebサーバ上のファイル保存される。
そして、ログアウト時には、以下のような処理が必要になる。
- サーバ側で保存しているセッション情報を削除
- クライアント(ブラウザ)側のCookie情報の削除
よって、phpでは以下のような処理を行う。
<?php // 空の配列を代入して、全てのセッション変数をクリアする。 $_SESSION = array(); // ブラウザのクッキーを削除。実際には、クッキーの有効期限に過去の時間をセットしている。 setcookie("PHPSESSID", '', time() - 1800, '/'); // セッションファイルを削除する session_destroy(); ?>
session_destroy();
でセッションファイルを破棄すれば、
$_SESSION = array();
のようなセッション変数を初期化する処理は不要ではないのか、と思ってしまったが、
私が動作確認したところ、同一スクリプト内ではsession_destroy();
実行後であっても$_SESSION
のセッション変数はクリアされておらず、
アクセス可能だった。
やはり、セッション変数の初期化とセッションファイルの削除を両方やっておくべきのようだ。
クッキーの属性
コッキーを発行する際、様々なオプション属性を設定することができる。
属性 | 意味 |
---|---|
Domain | ブラウザがクッキー値を送信するサーバのドメイン |
Path | ブラウザがクッキー値を送信するURLのディレクトリ |
Expires | クッキー値の有効期限。指定しない場合はブラウザ閉じるまで |
Secure | SSLの場合のみクッキーを送信 |
HttpOnly | JavaScriptからこのクッキーにはアクセス不可 |
Domain属性
デフォルトでは、クッキーはセットされた元のサーバのみに送信する。セキュリティ的には、これが安全なので原則としてDomain属性は設定しない。
Domain属性を指定するのは、複数のサーバに送信されるクッキーを生成したい場合だ。
例えば、Domain=example.jp
として生成したクッキーは a.example.jp
にも b.example.jp
にも送信される。
仮に、a.example.jp
サーバがSet-CookieヘッダでDomain=example.com
としても、このクッキーはブラウザに無視される。
セッションIDの固定化攻撃の手段にならないように、異なるドメインに対するクッキーは設定できないようになっている。
HttpOnly属性
クッキーに格納されたセッションIDを盗み出す手段として、クロスサイトスクリプティングによりJavaScriptを悪用してクッキーを盗み出すというものがある。 この属性を設定することで攻撃を難しくすることはできる。 phpの場合は、php.iniファイルで以下のように設定を追加する。
session.cookie_httponly = On
参考
体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践
- 作者: 徳丸浩
- 出版社/メーカー: SBクリエイティブ
- 発売日: 2011/03/01
- メディア: 単行本
- 購入: 119人 クリック: 4,283回
- この商品を含むブログ (146件) を見る
$_SESSION = array() と session_destroy(); の関係性。 - PHP 解決済 | 教えて!goo
PHPでBasic認証サンプル
Web開発に携わっていれば、Basic認証に触れる機会は必ずある。今回、基本的な仕組みを整理してみた。
Basic認証
サーバがクライアント(ブラウザ)にBasic認証を要求する場合、
WWW-Authenticate: Basic
ヘッダがあるステータスコード401
のレスポンスを返す。
それを受けて、ブラウザは、Base64エンコードされたユーザ名とパスワードを、Authorizationヘッダに付与してリクエストを送る。
Authorization: Basic ('ユーザ名:パスワード'をBase64でエンコード)
PHPの実装サンプル
以下は、phpでの簡単なBasic認証の実装例だ。 あくまで動作確認のため、ユーザ名、パスワードに何かしら入力があれば認証を通す、という簡単なものだ。 なお今回、phpを動かすwebサーバ環境の構築については触れない。
basic_authentification_sample.php
<?php $user = @$_SERVER['PHP_AUTH_USER']; $pass = @$_SERVER['PHP_AUTH_PW']; if (! $user || ! $pass) { header('HTTP/1.1 401 Unauthorized'); header('WWW-Authenticate: Basic realm="Basic Authentication Sample"'); echo "ユーザ名とパスワードが必要です"; exit; } ?> <body> 認証しました<BR> ユーザ名:<?php echo htmlspecialchars($user, ENT_NOQUOTES, 'UTF-8'); ?><BR> パスワード:<?php echo htmlspecialchars($pass, ENT_NOQUOTES, 'UTF-8'); ?> <BR> </body>
phpは、authorizationヘッダに付与されたユーザ名、パスワードにそれぞれ
$_SERVER['PHP_AUTH_USER']
と$_SERVER['PHP_AUTH_PW']
で取得している。
動作の流れ
まず、上記phpファイルにHTTP GETリクエストでアクセスする。 この時、リクエストヘッダにAuthorizationヘッダはないため、ステータスコード401 Unauthorizedが返ってくる。
401 Unauthorized
認証が必要である。Basic認証やDigest認証などを行うときに使用される。 たいていのブラウザはこのステータスを受け取ると、認証ダイアログを表示する。
ブラウザが表示したダイアログにユーザ名、パスワードを入力して送信すると、ブラウザは再びGETリクエストを送信する。
この時はAuthorizationヘッダにBase64エンコードされたユーザ名、パスワードが付与されている。
前述のPHPのコードはサーバ変数でユーザ名、パスワードにアクセスしhtml上に表示する。
ステートレス
これ以降、同じURLにアクセスしても認証ダイアログは表示されないが、それはブラウザが記憶したauthorizationヘッダを毎回自動的に付与してリクエストを送っているからである。HTTPもBasic認証もステートレスで、ログインという状態が保存されている訳ではない。
参考
体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践
- 作者: 徳丸浩
- 出版社/メーカー: SBクリエイティブ
- 発売日: 2011/03/01
- メディア: 単行本
- 購入: 119人 クリック: 4,283回
- この商品を含むブログ (146件) を見る
JavaScript: 変数宣言の巻き上げ
変数宣言と初期化
jsでは通常、以下のように変数を宣言し、値を代入する(初期化)。
var str; // 宣言 str = 'hello'; // 値を代入(初期化)
一行で書くこともできる。
var str = 'hello';
宣言の巻き上げ
jsでは変数の宣言は、関数スコープの先頭に巻き上げられる。
例えば、以下のようなコードがあったとする。
function sayHello() { console.log(str); var str = 'hello'; }
これは、次のように動作する。
function sayHello() { var str; // 宣言、undefinedの値が割り当てられる console.log(str); // 出力: undefined str = 'hello'; // 代入(初期化) }
つまり、
- 変数宣言は、関数スコープの先頭に巻き上げられ、その変数にはundefinedの値が割り当てられる。
- 変数の代入(初期化)の位置は変わらない。
スコープチェーンの上昇
JavaScriptエンジンは、変数宣言をローカルスコープからグローバルスコープに向かって調べていく。
以下のコードの実行を考える。
var str = 'hello'; function sayHello() { console.log(str); // 出力: 'hello' } sayHello();
関数sayHelloを実行して、console.log()が変数strを要求すると、JavaScriptエンジンはまず変数strがローカルスコープで宣言されているかを調べる。 この場合、変数strはローカルスコープで宣言されていないので、次にグローバルスコープを調べて、宣言を見つけて値を返す。
では、次のコードはどうなるか。
var str = 'hello'; function sayHello() { console.log(str); // 出力: undefined var str; // ローカルスコープでも変数宣言 } sayHello();
変数strがローカルスコープでも宣言されている。 この宣言は関数先頭に巻き上げられるので、グローバルスコープを調べる前に、この宣言を見つけて出力する。 ローカルスコープでは宣言のみにで初期化はされていないので、出力はundefinedだ。
参考
シングルページWebアプリケーション ―Node.js、MongoDBを活用したJavaScript SPA
- 作者: Michael S. Mikowski,Josh C. Powell,佐藤直生,木下哲也
- 出版社/メーカー: オライリージャパン
- 発売日: 2014/05/24
- メディア: 大型本
- この商品を含むブログ (1件) を見る