Railsはどうやって500やdebug用のエラー画面を出しているのか

関心

素の Rack middleware はただの玉ねぎ構造で、Exception は Exception で rescue しなければそのまま一番外側の middleware まで伝播して、ユーザーに適切に status code を伝えることなく果ててしまうはずである。

しかし実際には Rails などのフレームワークを使った場合、それっぽいエラー画面をユーザーに伝えることができるようになっている。

それでいて ExceptionNotification gem など、自分で use した middleware の中ではやはり例外を例外のまま拾うことができる。

ということは、通常の

Rack::Builder.new do
  use ..
  use ..
  run ..
end

とは異なる何らかの middleware 群がフレームワークによって外側に配置されているはずである。

結論

予想通り、いい具合に例外を適切な response に変換する middleware が外側の stack にいる。したがって通常のアプリや独自の rack middleware を書く際に例外は例外のまま投げっぱなしでよい。

いざコードリーディング

※ ちょっと事情があって古い Rails を読んでいるので最新のものでは細かい部分で食い違いがあるかもしれないが、基本的な構造は変わっていないはず

railtie の中で middleware を探していくと Rails::Engine にそれっぽい記述が見つかる。

  • Rails::Engine の中で default_middleware_stack を呼んでいて
  • これが ActionDispatch::MiddlewareStack.new して…途中すっ飛ばして
  • Rails::Application::DefaultMiddleware#build_stack の中でデフォルトで定義済みの middleware を use していく。これが

https://guides.rubyonrails.org/rails_on_rack.html#action-dispatcher-middleware-stack

に挙げられているもの。

この中で中盤くらいに ActionDispatch::ShowExceptions という middleware があって、こいつに ActionDispatch::PublicExceptions という別な middleware を与えてある。

default_middleware_stack.rb の以下のコードがそれである。

         middleware.use ::ActionDispatch::ShowExceptions, show_exceptions_app

通常の Rack::Builder で use している場合の Middleware.new(app, *args, &block ) とは別な形でもう一つの middleware が与えられていて、 rescue Exception した際にはこの show_exceptions_app として PublicExceptions が呼ばれるようになっている。該当部分は以下の通り。

show_exceptions.rb の中身はこう。

   def initialize(app, exceptions_app)
     @app = app
     @exceptions_app = exceptions_app
   end

   def call(env)
     @app.call(env)
   rescue Exception => exception
     if env['action_dispatch.show_exceptions'] == false
       raise exception
     else
       render_exception(env, exception)
     end
   end

そして PublicExceptions の中では

   def render_html(status)
     path = "#{public_path}/#{status}.#{I18n.locale}.html"
     path = "#{public_path}/#{status}.html" unless (found = File.exist?(path))

     if found || File.exist?(path)
       render_format(status, 'text/html', File.read(path))
     else
       [404, { "X-Cascade" => "pass" }, []]
     end
   end

こんな風に決め打ちで public/ 以下からerror 用の HTML を render している。なるほど。

ダイソーのシールがやわすぎる

クリアホルダーあるじゃないですか。あの透明でペラペラで数枚の紙を中に入れておけるやつ。こまい仕事をやっつけていくにはいいんですけど、さすがに容量が小さすぎるので、数が増えちゃうんですよね。で、それをまとめるファイルを買ったんですよ。ダイソーで。

そのファイルにダイソーのシールが悪目立ちする感じで貼られてたんではがそうとしたんです。

……。失敗。

09:13:57 >wtnabe< ダイソーのシールは粘着力に対して紙がやわすぎる
09:14:33 >wtnabe< シールはがそうとする -> 紙の方が弱くて途中で破れる
-> いーってなる <- イマココ

その後、延々と消しゴム掛けて丁寧に剥いでいきましたとさ。いくらファイルが安く手に入ってもこの時間のロスを考えるとイマイチな気がしたのでした。

なんかどうも個人的には100円ショップってあんまりうまく活用できないというか、買うとガッカリすることが多い気がします。なんでだろう。いい買い物した!って思うことが少ないんだなー。

結局日本語周りをまとめた

例によって嘘、大げさ、紛らわしい場合はツッコミぷりーず。

基本

  • 5.8 以降では Perl は内部的に文字列を UTF-8 で扱うものとする
  • Perl 的に認められた文字列には UTF-8 フラグがつく
  • UTF-8 フラグのついていないものでも人間が文字列として認識するのは自由

use utf8;

コードが UTF-8 で書かれていることを宣言する。もしかすっと将来的にはこれがデフォルトになるのかも。

マルチバイト文字列を正しくマルチバイト文字列として扱おうとしてくれるが、副作用としてマルチバイト文字を print したときに警告が出るようになる。

逆につけなくても今まで通り日本語をコード中に書くことはできる1。これをそのまま print することは可能。euc-jp だろうが utf-8 だろうが同じ手法が使える。もちろん Shift JIS のように地雷を踏みやすいエンコーディングを選ぶ際は自己責任で。ファイルの読み書きも従来通りに動かせます2

ただし、use utf83しておかないと、シリアライズ系のものが軒並み \xXX 形式になってしまい、コマンドラインでの作業効率はよろしくない。つけてもつけなくても同じ結果になるモジュールもあるが、最近の UTF-8 フラグを解釈してくれるモジュールを扱う場合はつけておいた方が少し幸せになれるかも4

use utf8 しておくことで他にも嬉しいケースはあるかもしれないんだけど、あんまり詳しく調べてません。正規表現マッチを日本語で書けるような気がする。

binmode STDOUT => ":utf8";

UTF-8 フラグのついたマルチバイト文字列を print するときに UTF-8 フラグを落としてくれるので、警告が出なくなる。use utf8 したときはこれ書いておかないとコマンドラインでの作業が邪魔くさくなる。

もちろん一つ一つ

Encode::encode()

して出すっつー酔狂な選択をしてもいいけど、そんなの面倒じゃん。

use encoding CHARSET;

Perl 5.8 で内部的には UTF-8 でイクっつーのは決まったんだけど、そんでもどうしてもコードを Shift JIS で書きたいやい、UTF-8 なんてやだいやだいという場合にしゃあなしで使うことを許されるもの。

use encoding "euc-jp";

って書いたら euc-jp で書いてあるコードでも UTF-8 で書かれているのと同じようにマルチバイトな文字列として扱ってくれて、なおかつ STDIN も STDOUT も euc-jp を期待して動いてくれる。

当然、UTF-8 フラグ周りの警告も出ない。use utf8; とは排他と考えるべし。(実際には使えるみたいだけど、「混ぜるな危険」が基本です。)

use open

スクリプトもデータも euc-jp なんだけど、もうターミナルは UTF-8 で統一したいし、他の UTF-8 前提で動いてるアプリと組み合わせたい、という場合は、コード中にマルチバイトなリテラルを書いてなければ、

use open IN => ":euc-jp";
use open OUT => ":utf8";
binmode STDOUT => ":utf8";

とすることでそれなりに対処できる。上の例では euc-jp の入力、UTF-8 な出力を期待して動く。

ターミナルだけの問題なら screen でも対応可能だけど、他のアプリと繋げたいという場合は open を使うと楽できると思う。

use Encode;

使ってないんでよく分からないけど、これは変換以外に気にするポイントはないのかな。

なんかねぇ、似たような単語でいろいろな機能が動くんで、ものすごく分かりにくいです。

参考

  1. Perl 5.8.8 で確認した。 

  2. 5.8.0 では暗黙のうちに UTF-8 フラグが立っちゃってぎゃっ!と言う人が続出したらしい。 

  3. あるいは use encoding 

  4. シリアライズは Data::Dumper よりも YAML の方がいいような気がしてきた。でもどっちを使ってもハッシュを与えたらリストと勘違いしちゃうのでハッシュリファレンスを与えなきゃダメっつー辺り、やはりいや〜な気分にさせてくれる。 

やっぱ Perl しんどい

Perl 5.6 以降の Unicode 周りの話は華麗にスルーしてきたんだけど、あらためて昔のスクリプトをどうにかしようと思い、久々に Perl を触って悪戦苦闘。まずデータ構造の扱いにくさに泣きそうになる。ついで日本語。なんか Unicode がどうのこうでやたらといろんな方法がある。無理。こういうとき Perl の TMTOWTDI は本当に腹立たしい。どのやり方でもエレガントにできない言い訳じゃないのかと。

とりあえず設定を全部 YAML に逃がして、最終的に Perl でないもので動くように(!)持って行きたいがための作業なので、面倒なところはやはりスルーしつついくのがベストのような気がして来た。幸いこれ、日本語を直接読み書きしなきゃいけないものじゃないしな。

RD のディスクが認識できない

ずーーーーっと電源入れっぱなしだった RD の電源を、夜中に目が覚めたときにふいに落としてみた。LED がまぶしかったっていうのもあるし、ずっとあっちいしなぁと思ってよかれと思ってやったのだ。

しかし、おかげでハードディスクを認識しなくなった。電源を落としたことで籠っていた熱を吐き出すことがまったくできなくなったんだろうか。あんまりだよ。だったら電源落とさずに頑張ってくれればよかったのに。お前は落とそうとしているがおれは落とさんぞ、と。

まだ1年ちょいしか使ってないのにさぁ、そりゃーねーだろ!東芝さんよぉ!

どうせ保証切れてるだろうからハードディスク引っこ抜いてイメージコピーしたろか。ちくしょうめ。あーちくしょうめちくしょうめ。どないやねん。本体は壊れてなくてもドライブがやられたらまったく意味ねーんだよな。

……。

自動バックアップできればいいのか?

[2006-08-06 追記]

かなり手こずったがとりあえず換装できた。最初カバーを開けることができずに試行錯誤。普通に引っ張れば抜ける、みたいに書いてあるページがあったんだけど、実際には後ろの3本とサイド4本のねじを外して、横から見て ∠ の形に開けていくと「バキッ」と音がしてビビるが普通にどこも痛まずに外れる。おっかねーな、おい。

で、動作報告のあった Seagate の ST3160212A に換装。相変わらず認識できませんというメッセージが出たが、初期化したら普通に 160GB 認識している模様。ほんとは HGST の方がいいみたいなんだけど、動かなかったとき面倒くさいので無難なものに。まだ録画や DVD の読み書きをやっていないので本調子なのかどうかは分からないけど、それはおいおい確認ということで。あと、もとのディスクを dd で救えるかどうかもまだやってない。それは今度ゆっくりやろう。

ハードディスクの外れを避けたのは手持ちの金が少なかったのもあるけど、TV のアンテナがレコーダを経由しないと繋がらないので長時間外しているわけにもいかないし、家電品感覚で配線と設置しちゃってるんでメンテナンス性がすこぶる悪く、何度もやりたくなかったから。なかなか難しいねぇ。今度置くときはこういう消耗品の入ってるモノの配置はもっと慎重に考えよう。

教訓:夏場はファンを止めるな。

[2006-08-06 さらに追記]

とりあえず試しに1時間番組を録画。これと言って問題ないみたい。ディスクを変える前に DVD を再生したみたときは 27分再生したところでピタっと止まってまともに操作できなかったんだけど、それは HDD のトラブルが波及したものと判断していいかな?

なんか前より熱くないような気がする。元々入っていたのは Maxtor だけど、ユーザーサイトで「高発熱」とは書いてない型番だったんだけどなぁ。やっぱ Maxtor は熱いっつーことなんかなぁ。前に自宅サーバで使ってたやつも Maxtor であっちっちで夏場に壊したんだよな。どーも Maxtor とは相性が悪いのかもしんない。

戻り値のブルース

頭の中でぼんやりとプログラムの構造を考えていたときの話やけども。

日本語で if とか関数とかの大枠だけ思い描いているときってあるやん。

ほんでそんときに例えば細かい条件がいっぱいある処理を思いついてもうて。

あぁそれやったらオブジェクトにして条件全部メンバ変数のハッシュに持っとって、「なんかくれ」って言われたときにその条件全部見て、必要な値をハッシュに詰めて返してあげれば。

あとは「くれ」って言ったやつがその値を丸呑みしてハッシュのまま使うのか、

一個一個バラして変数に詰め直して丁寧に書いてあげるのかは、

自由だ〜!

戻り値の扱い is ふりーだーむ。戻り値の扱い is ふりーだーむ。

Say !

戻り値の扱い is ふりーだーむ。戻り値の扱い is ふりーだーむ。


…って冗談じゃなくマジでそう思って目の前が明るくなった。

誰かオチつけて。

ini_set( upload_max_filesize ) は 4.2.3 まで

PukiWiki の attach.inc.php 内に

ini_set('upload_max_filesize', '2M');

という行があるが、この記述は PHP 4.2.4 以降は無効となる。これは upload_max_filesize が PHP_INI_ALL から PHP_INI_PERDIR1 に変わったため。

cf. PHP: Description of core php.ini directives - Manual

一応本家の BugTrack に投げて、FAQ に追記しておいた。1.4.6 までに反映されるかな?

  1. か、PHP_INI_SYSTEM. マニュアルの版によって記述が違う。 

例えばスウェイバックと呼ぶのはどうだろう

とある思いつきについて

あれ、無断リーブがネタバレしてる。出遅れってのは痛いなぁ。

実は前回のものは急いで書いたので本当に盛り込みたい内容が盛り込まれていない。

  • 無断リーブに代わるカジュアルな名前を考える
    • 着メロなどのように少し縮めた言葉が普及するような、そんな形が最も望ましい。トラックバック → トラバ、ホームページ → ホムペ、のような変化が生まれ、もとの意味がぼやけてしまう言葉の方が「強い」。
  • 無断リーブを力強く肯定する。ただし根拠を技術や合理性に求めない
    • 権威付けによる正当性の確保も盛り込む

という辺りを書きながら考えていたんだけど、これは結構時間を掛けて練らないとダメだなぁと思って、とりあえずモヒカン編だけ書いておけ、という感じで上げておいたのである。

なぜこういう方向で考えようと思ったかというと「『リーブは自由』ってフレーズは非モヒカンが言ったらダメなんじゃないか?」と思ったからである。この「リーブは自由」はとてもおいしいえさだった。少なくとも自分にとって。

そこから無断に無断で返すのはモヒカン流じゃないのか?という言葉にも繋がったのだけれど、「どつき合い」という表現はまずかったらしい。そもそもモヒカンに対する理解が足りないことが完全に露呈された格好だ。自分の中ではこれは男の子が河川敷の殴り合いで友情を確かめ合うような、そんなイメージだったのだけれど、そもそもモヒカン族はこんな方法で友情を確かめ合うのかどうか確認していない。うかつだった。

ということでタイトルに戻して無断リーブをスウェイバックという名前にしてしまうのはどうだろう。スウェイバック → スウェバを期待。しかし意味付けの考察は浅いのでもっといい名前がきっとある。つーかそもそもパンチ当たってるんだからスウェイも何もないだろう、というマジツッコミをもらってもやり返せないので、あしからず。

もちろん今回はもとの無断リーブの遊びの意味を理解したうえで、おれは違う遊びを考えてるんだぜ、という釈明であって、無断リーブという言葉や遊びそのものを否定する気はない。ただ、自分としては原理主義派のモヒカンが叩きやすい名前を付けた方が(仮に無断リンク議論がこの名前を利用して進むとしたら)より議論が発散しやすく、面白くなるんじゃないかなと思っている。この遊びは恐らく「いわゆるスウェバ」などの言葉が派生してきた時点で名付け親の勝ちなのだろう。

AOpen の H420

サイズと値段の割にはなかなかよさげな感じのケース。ほんとはフロントから吸気してほしいけど、このツクリじゃ無理だよなぁ。

http://aopen.jp/products/housing/h420.htm

どうかな?

漫画のパート2ブーム

たぶんキン肉マンがはしりだと思うんだけど、

  • キン肉マン
  • 銀河
  • リングにかけろ

といったかつてジャンプで一世を風靡した漫画の続編が次々と始まった時期があった。(銀河の続編は『WEED 〜銀河伝説〜』 )

  • CITY HUNTER → Angel Heart

は香という超不遇の娘がすでに死んでしまっていたというものすごい展開からスタートしててびっくりしたものだ。いやほんとひどい話。香は犯罪者の娘で親を警官に殺されてて、育ての親も血の繋がらない兄弟も捜査中に死んでて、おまけに本人はやっと幸せになろうかってときに事故死ですよ、ああた。誰にデスノート使われてるんですか、ほんとに。

そして今日は

  • ミスター味っ子
  • (スーパー)ドクターK

の続編が始まっているのを知ってしまった。マガジン系も来たかーと。

ここまできたら

  • うる星やつら
  • タッチ

とか、サンデー軍団も続編作りましょうよ。タッチはアニメが独断先行で続編作ってるけど、それをぶち壊すいい話にしましょう!

ちなみに、

  • ドカベン

はもういいです。プロ野球編が始まった段階でそりゃ無理だろーと思っていたら、知三郎は本編に出てない(水島高校球児総出演の『大甲子園』のみ)のにサクっと登場してるし、そうかと思えばほとんど一人で明訓と対等に戦い、延長18回引き分け再試合で2試合目に 160km/h オーバーの記録を打ち立てた球道くんは遅れて参戦した挙句ロクな活躍してないし。もう高校時代のすごさがぶっ飛びまくり。アメリカ留学って設定もどないやねんと。留学してその程度かいと。それなら今の訳分からん球団で「高校生ドカベン」時代の連中だけ特別扱いするときに「メジャー帰り」で登場させるべきだったのにーと思うわけですよ。えぇ、私は球道くんが好きなんです。不知火よりも球道くんです。小倉時代の誰か出てこないかなー。

新潟県人として言いたい。水島先生よぅ。そりゃーないんでないかいと。あぶさんの無茶苦茶さはいいですよ。あれは主役はっきりしてるからね。でも今のドカベンのそれはちょっとどうかと。もったいないです。

たまには漫画を熱く語る日があってもよかろう。

Lhasa は 0.19

0.18 にはまだバグがあった模様。まだあまりミラーされていないので本家から落とすべし。

とりあえず様子見

なんか肩、首より腰が痛いような気がするのはなんでだろう。。。単に一つ気になる箇所が減ったら他が気になるってだけだろうか。

まだなんかちょっと味覚がおかしい気がする。朝のコーヒーがあまりおいしくない。

About

例によって個人のなんちゃらです