Yosemite 環境に Homebrew から rbenv を用いる際にセキュリティソフトが悪さをしているかもしれない

ふわっとしたタイトルで申し訳ないのですが、なにぶんマシンそのものがクラッシュしてしまうため、あまり検証もできていません。実際に起こった事象の報告と、一応の解決策のみ記載しておきます。

何が起こるのか

実際に問題が起こった環境の場合 Kaspersky でしたが、これを起動した状態で

brew install rbenv ruby-build

ここまでは通るのですが、この後実際に Ruby をインストールしようと

rbenv install ruby x.x.x

を叩くとクラッシュ、という感じです。

どうすればいいのか

起動中の Kaspersky を終了させて、念のため Homebrew を一旦削除した上で再インストールし、改めて上の手順を実行します。
少なくとも筆者(の、同僚)の環境ではこれで問題無くインストールができ、その後はセキュリティソフトを起動した状態でも正常に動作する事が確認できました。

Rails のカスタム例外補足時に順番に注意が必要な件

次のようなコードを Rails 4.0 系の controller に記述すると

  rescue_from ActiveRecord::RecordNotFound, with: :render_404
  rescue_from ActionController::RoutingError, with: :render_404
  rescue_from Exception, with: :render_500

内部では ActiveRecord::RecordNotFound が出ている場合でも一番下の Exception を拾う方が優先されて render_500 が実行されてしまいます。下のような順番で記述すれば問題ありません。

  rescue_from Exception, with: :render_500
  rescue_from ActiveRecord::RecordNotFound, with: :render_404
  rescue_from ActionController::RoutingError, with: :render_404

redirect_to とフラグメント修飾子と実体参照

前振り

フラグメント修飾子とは、今回の話の範囲では
http://api.rubyonrails.org/classes/ActionDispatch/Http/URL.html#method-c-url_for
というアドレスに含まれる「#」以降、つまり「method-c-url_for」の部分になります。

そして Safari を使ってリダイレクトを行うと、このフラグメント修飾子が消えるというのが今回発生した問題でした。

http ヘッダにおけるフラグメント修飾子の扱い

RFC にきちんと定義されています。
ftp://ftp.rfc-editor.org/in-notes/rfc2396.txt

非常に長いのですが、結論から言うとヘッダにフラグメント修飾子をつける事はできない、との事。

Rails における解決方法

Rails においては redirect_to を使う際に :anchor オプションをつける事で解決できます。

redirect_to hoge_path(anchor: 'fuga')

問題の解決だけを行いたいならここまでで完了となります。以下は動作が気になって仕方ない人向け。

どうやってそれをやったのか

前提でヘッダにフラグメント修飾子は含まないと述べたのに何故 Rails は実装できているのか、気になったので調べてみました。
最終的にたどり着いたのが

actionpack/lib/action_dispatch/journey/router/utils.rb

このファイル。記事執筆時に見つかった github 上のリンクも添付しておきます。

https://github.com/rails/rails/blob/08754f12e65a9ec79633a605e986d0f1ffa4b251/actionpack/lib/action_dispatch/journey/router/utils.rb

使われているのは escape_fragment というメソッドなのですが、文字列のエスケープを行い「#」を「%23」に変換していました。

RMagick で PDF を jpg や png に変換する

RMagick が内部で使用している ImageMagick には PDF を jpg などの画像に変換する機能があります。

convert test.pdf test.jpg

一番簡単な使い方は上の通り。手元の環境では特に jpg が残念な画質になりますが、そのあたりはオプションで(ある程度)補完が可能です。これをそのまま叩いてもいいのですが色々な配慮で Rmagick から実行するケースについて記載します。
テストは Mac を使い Ruby 2.0 で行いました。

準備

準備と言っても RMagick が正しくインストールされている環境であれば

require 'RMagick'

を書くだけで終わりです。

実際の変換

簡単なコードは

require 'RMagick'
file_name = "test.pdf"
image = Magick::Image.read(file_name)
image[0].write(file_name + ".jpg")

以上で終わりです。image[0] という記述で察しがつくとは思いますが image には PDF が1ページずつ読み込まれています。

応用編

オプションの指定

convert コマンドの各種引数にあたる値はブロックを使って設定します。

require 'RMagick'
file_name = "test.pdf"
image = Magick::Image.read(file_name) do
  self.quality = 100
  self.density = 200
end
image[0].write(file_name + ".jpg")

詳しいオプションについては公式ドキュメントを参照してください。

https://github.com/rmagick/rmagick

ページ指定読み込み

ページ数の多い PDF を読み込むとメモリの消費は増え、読み込みに時間もかかります。必要なページが決まっているのであれば、次のような指定で特定ページのみ読み込む事が可能です。

require 'RMagick'
file_name = "test.pdf[2]"
image = Magick::Image.read(file_name)
image[0].write(file_name + ".jpg")

オフセットの初期値は 0 なので、この場合 3 ページ目だけを読み込み、画像に変換する事ができます。

追記

環境によっては ghostscript がインストールされていないため PDF が正しく開けないかもしれません。パッケージは大体の環境に存在するはずなので、確認の後、適宜インストールしてください。

Windows Server 2012 R2 で PowerShell 製のバッチを使う

今回の目標

Windows のジョブに登録したバッチ処理で「特定のディレクトリから最終更新日時が一週間以上前のファイルを削除する」という目的を達成します。
なお、この処理はやむにやまれぬ事情で作成に至ったものであり、私は PowerShell の文法を順序立てて学習していないため冗長な箇所などあるかもしれません。

ps1 ファイルの作成

処理の本体になる PowerShell のファイルを作成します。
中身は以下のコードのような感じですが、バックスラッシュは通常の円記号とは別の文字として認識されるため注意してください。

$path = "C:\path\to\batch"
$tgt = (Get-Date).AddDays(-7)

Get-ChildItem -Path $path | Where-Object {$_,LastWriteTime -lt $tgt} | Remove-Item

bat ファイルの作成

上で作成した PowerShell は対話式コンソールから実行可能ですが、バッチとして動かす場合適切な実行権限を与えないとエラーになります。仕方が無いので .bat ファイルから権限の変更→ ps1 ファイルの実行→権限を戻す、という流れで動作させるようにします。

以下のサイトを参考に、というよりほぼコピペで作成しました。
http://no6.hatenablog.com/entry/2014/01/31/161608

一点、元のサイトでは %CD% でカレントディレクトリを指定していますが、バッチの実行時には exe ファイルの存在する位置がカレントディレクトリになります。そのためフルパスで記述した方が安全でしょう。

タスクの作成

普通にタスクスケジューラから登録を行うだけなのですが、「最上位の特権で実行する」にチェックを入れる事と、履歴を残す設定にしないとうまく実行されたかどうかも分からない点に注意してください。

追記、ネットワークドライブの取扱

ネットワークドライブはバッチから参照する場合改めてマウントし直す必要があります。具体的には以下のようになります。

net use Q: \\127.0.0.1\share password /user:user

$path = "C:\path\to\batch"
$tgt = (Get-Date).AddDays(-7)

Get-ChildItem -Path $path | Where-Object {$_,LastWriteTime -lt $tgt} | Remove-Item

net use Q: /delete

ところによりバックスラッシュだったりスラッシュだったりするので注意してください。

2015

                       コングラッチュレーション
             ,―==7     Congratulation!   コングラッチュレーション
             |く ___ _>                    Congratulation!
             fll`ーU+'
             `''、 ー=|      おめでとう・・・・・・・・!
          _,,..-´:|ヽー-;ー..,,_
.  ,−=-, ,,..-‘≡≡:| ><´|≡::|ヽ    おめでとう・・・・・・・・!  おめでとう・・・・・・・・!
.  | l____ヽ.|≡l≡≡≡| |::| |≡:::/::|
.  |(llー´_ヽ|≡|≡≡≡|.|:::|l≡::/::::|      新年あけましておめでとう・・・・・・・・・・・・!
.. 4 l__`=|_|≡:|≡≡≡::||:::|'≡/≡|
/|\,.・|::≡:|ヽ|≡≡≡≡≡:::/|≡::|                         _,,.........、
≡|/}:ヽ|:≡|::::|{≡≡≡≡≡:::{ .|≡::|                        ヽ_,,   ヽ
≡:| |:::|l≡:|≡|:|≡≡≡≡≡:::|. .|≡::|                        /_>   |
:::≡l|:::|'≡:|≡:|::|≡≡≡≡≡:::|. .|≡::|                       |7 llう.. |
≡≡≡≡/|≡ヽ≡≡≡≡≡::::|. ..|≡::|.    z-..,〃、             ム__ ll´.. |
::≡≡≡::/ ヽ≡ヽ≡::|―、≡≡::l ..|≡::|   /    ミ              1´/ヽ==,...
::≡≡≡|   \≡ヽ::|  ヽ≡≡l  .ljヽl  |   刀、ミ           _,,,..-`‐三=ー-
::≡≡≡|    |ヽ/ー.、.. ヽ≡≡l.  .|/  |  ノ= ∠i         /ヽ、≡≡≡≡≡
:|¬、≡≡ヽ.  |≡ゞー=ッ  |≡≡|   __/ (ll ー゜\|ヽ.       /≡::ヽ≡≡≡≡≡
:|  ヽ≡≡ヽ |≡≡ヽミ.   |≡≡|  l|. ll7| ヽu=/l二ll二l'''ヽ  /≡:::/≡≡≡≡≡
:|   ヽ≡≡ヽ≡≡|     |≡≡|  | | llヽ|w-ヽ/Nヽll  |  | /≡:::/≡≡≡≡≡≡