Rails 5.1が出ていたので、このブログをアップグレードしてみました。

Rails 5.1: Loving JavaScript, System Tests, Encrypted Secrets, and more | Riding Rails
http://weblog.rubyonrails.org/2017/4/27/Rails-5-1-final/

(1) GemfileのRailsのバージョンを5.1.0にする

(2) 以下のコマンドを実施。

bundle update
rails app:update


Rails 4系からのアップグレードということもあって、sass-railsやcoffee-railsなどのgemのバージョンを変更しないと依存関係の問題でbundle updateが失敗しました。まぁ、こんなに長く放置しているアプリケーションも珍しいと思うので、細かくRailsのバージョンを上げていれば問題はないはず・・・です。

  • config/boot.rbは上書き
  • config/routes.rbはスキップ
  • config/application.rbは上書き
  • config/secrets.ymlは上書き
  • config/environment.rbは上書き
  • config/environments下のファイルは適宜マージ

development環境のconfig.file_watcherはActiveSupport::EventedFileUpdateCheckerは無効にして、ActiveSupport::FileUpdateCheckerを使うようにしました。
これは、Vagrant上で開発していると、共有フォルダのファイルの変更が検知できない事があるためです。

また、以下の問題を対応しました。

Rails 4.2を5.0に上げたら、production環境でautoload_pathsが効かなくなった
http://akasata.com/articles/318

ソースコードの書き換えとしては、redirect_to :backをredirect_backで書き換えたくらいです。
その他、特に問題ありませんでした。

以下、参考情報(と言うより一次情報)です。

A Guide for Upgrading Ruby on Rails - Ruby on Rails Guides
http://guides.rubyonrails.org/upgrading_ruby_on_rails.html


Posted by あかさた
趣味コードをRails 4.2から5.0に上げたら、production環境だけconfig.autoload_pathsが効かないという現象に遭遇したので、対策をメモっておきます。

Rails Guideによると、config.eager_loadとconfig.cache_classesがtrueだとconfig.enable_dependency_loadingがfalseになり、autoloadingが無効化されるようです。development環境ではこの2つをfalseにしている事が多いでしょうし、production環境ではtrueにしていることが多いと思うので、この問題に遭遇する人は多いのではないでしょうか。

Configuring Rails Applications
http://guides.rubyonrails.org/configuring.html

では、config.enable_dependency_loadingをtrueに設定すればいいのかというと、実際それで動くようにはなりますが・・・将来的にはこのオプションは削除されるようです。

Add option to enable dependency loading in production
https://github.com/rails/rails/commit/80b416f5e692ae79f4062f59fed6c7d7648a8af0

上記のコミットログにも、const_missingを利用しているアプリケーション向けに付けたオプションと書いてあるので、あくまで特殊なケースと位置づけているのでしょう。

再度、Rails Guideを見返すとconfig.eager_load_pathsを見つけたので、これを使うことで解決することができました。

config.eager_load_paths << "#{Rails.root}/hogehoge"


■ 参考

rails commit log流し読み(2016/06/23)
http://y-yagi.hatenablog.com/entry/2016/06/24/063207

下記ブログでは、copy-on-writeの恩恵をうけるために本番ではautoloadを使うべきではないと紹介しています。

Don't forget about eager_load when extending autoload paths
http://blog.arkency.com/2014/11/dont-forget-about-eager-load-when-extending-autoload/

■ 備忘録

Rails 4.1.1を4.2.0にアップグレードした
http://akasata.com/articles/316

Posted by あかさた
Rails 4.2.0がでていたので、このブログをアップグレードしてみました。

Riding Rails: Rails 4.2: Active Job, Asynchronous Mails, Adequate Record, Web Console, Foreign Keys
http://weblog.rubyonrails.org/2014/12/19/Rails-4-2-final/

(1) GemfileのRailsのバージョンを4.2.0にする

4.2に限った話ではありませんが、一度新規アプリを生成してGemfileを見比べたほうがいいでしょう。
例えば4.2ではWeb Consoleのような新機能が追加されていますが、この機能を使うにはGemfileに該当するgemを追記する必要があります。

(2) 以下のコマンドを実施。

bundle update
rake rails:update


  • config/boot.rbは上書き
  • config/routes.rbはスキップ
  • config/application.rbは上書き
  • config/environments下のファイルは適宜マージ

Rails 4.2からrails sでbindingされるIPが0.0.0.0からlocalhostに変わった(※)ので、仮想環境越しのアクセスが失敗するようになっています。(セキュリティ上の理由があるようです。)その場合は、以下のようにするとよいでしょう。

rails s -b 0.0.0.0


※ 厳密にはRack 1.6での仕様変更を受けてのようです。詳しくは以下のブログにあります。

Rails4.2beta1をインストールして最初にはまったこと TECHSCORE BLOG

また、以下のページの「2 Upgrading from Rails 4.1 to Rails 4.2」も参考になる(と言うより一次情報ですね)ので、参照するとよいでしょう。

A Guide for Upgrading Ruby on Rails — Ruby on Rails Guides
http://guides.rubyonrails.org/upgrading_ruby_on_rails.html

Posted by あかさた
手元の開発環境でrroonga gemをインストールしようとしたら、ライブラリ(もしくはヘッダ)が足りないと怒られてコンパイルに失敗してしまいました。

gem install rroonga


そこで、以下の記事を参考にライブラリとヘッダをインストールしてから再度インストールを試したところうまく行ったので、備忘録としてメモっておきます。


rpm -ivh http://packages.groonga.org/centos/groonga-release-1.1.0-1.noarch.rpm
yum makecache
yum install groonga-libs groonga-devel
gem install rroonga


過去に試した時は事前にパッケージを入れなくてもrroongaをインストールできた気がするので、たまたま何か前提となるパッケージが足りなかったとかそういう感じだと思いますが。。。

Posted by あかさた
Rails 4.1.0が出ていたので、このブログをアップグレードしてみました。
例によって、作業ログを残しておきます。

Riding Rails: Rails 4.1.0: Spring, Variants, Enums, Mailer previews, secrets.yml
http://weblog.rubyonrails.org/2014/4/8/Rails-4-1/

(1) GemfileのRailsのバージョンを4.1.0にする

(2) 以下のコマンドを実施。

bundle update
rake rails:update


  • config/routes.rbはスキップ
  • config/application.rbは特に変化が無かったのでスキップ
    • (備忘録:4.0.2から4.0.4にアップグレードした時は少し変化があったので修正した記憶があります)
  • config/environment.rbは上書き
    • config/environments下のファイルは適宜マージ
  • その他細々と上書き
    • config/initializers/mime_types.rb
    • config/initializers/session_store.rb
  • config/secrets.ymlにsecret_token.rbの内容をコピーして、secret_token.rbを削除

注意点としては、セッションのシリアライズがRubyオブジェクトをMarshalする方式からjsonへのシリアライズに変更された関係か、私の環境では以下の様なエラーが出ました。

ActionView::Template::Error (795: unexpected token at {I"session_id:ETI"...


config/initializers/cookies_serializer.rbのcookies_serializerを:hybridにするとうまい具合にmigrateしてくれます。
(デフォルトは:jsonです。旧方式を使うなら:marshalを指定してください。)

Rails.application.config.action_dispatch.cookies_serializer = :hybrid


JSON方式に変更すると、DateTimeなどのようにセッションにRubyオブジェクトを含めていた場合に問題が出るかもしれないので注意する必要がありそうです。

Posted by あかさた
RailsのCookieStoreの脆弱性についていくつか報告記事が出ていたので、内容を検討してみました。

Ruby on Railsにcookie保存関連の脆弱性、2000サイトで放置状態
http://www.itmedia.co.jp/enterprise/articles/1311/27/news041.html

Rails SessionにCookieStore使った時の問題点
http://oauth.jp/blog/2013/09/26/rails-session-cookie/

読み合わせていくと、以下のような問題があるようです。

  • Cookieの情報が抜かれることによって、セッションをハイジャックされる可能性がある
    • Rails 2系にはXSS脆弱性からCookieの情報が抜かれる可能性がある
    • Rails 3/4系でもCookieが盗聴される場合は危険
  • セッションをサーバーサイドで管理していないことに問題がある

詳しく見ていきましょう。

このためクロスサイトスクリプティング(XSS)などの攻撃を仕掛けられて情報を盗まれた場合、ユーザーのログイン情報が悪用される恐れがあるという。

http://www.itmedia.co.jp/enterprise/articles/1311/27/news041.html


Rails 4より前のCookieStoreは署名を使った改ざん防止は入っていますが、Cookieそのものは平文で保存されています。

XSSでCookieの情報が抜かれる脆弱性は、CookieのHttpOnly属性が有効になっていなかったRails 2系にはあったように思います。(昔の話なので自信がありませんが。。。)
Rails 3系ではHttpOnly属性が有効になっているので、XSS脆弱性だけで抜かれる可能性は低いです。

Rails 4では暗号化されているので、こういった危険性はさらに低くなります。ただし・・・

しかしマクナマラ氏はThreatpostに対し、「バージョン4.0以降にも問題は存在する。攻撃者が暗号化されたcookieをサーバに送信すれば、cookieのコンテンツを解読しなくても被害者になりすましてログインできる」とコメントしている。

http://www.itmedia.co.jp/enterprise/articles/1311/27/news041.html


このように書かれている通り、Cookieを盗聴されると内容が暗号化されていてもセッションハイジャックされる可能性があります。

マクナマラ氏は解決策として、セッション情報がクライアントサイドではなくサーバサイドに保存されるcookie保存のメカニズム使用に切り替えるよう促している。

http://www.itmedia.co.jp/enterprise/articles/1311/27/news041.html


これは少し言葉足らずに思いました。

例えば、MemcacheStoreを使ったとしても、Session IDをクライアントに置く以上、同様の問題があるはずで、MemcacheStoreに切り替えたからはい安心という種類の問題ではありません。(いや、おそらく大元ではそういう認識で話していないでしょうが。)

本質的な問題点については、以下の記事が詳しいです。

Rails SessionにCookieStore使った時の問題点
http://oauth.jp/blog/2013/09/26/rails-session-cookie/

  • サーバーサイドでセッション管理していないと、セッションがユーザーやセキュリティ上の意図を超えて有効になってしまう恐れがある
    • (a) 例えば、パスワードが漏れて変更した場合など、そのアカウントに紐づく全てのセッションが削除されるべき(少なくともパスワード入力を要求すべき)状況で対処することができない
    • (b) ユーザーがログアウトしても、ログイン中のCookieを保持していることによって、ログアウトしたはずのセッションでログイン状態を保持することが可能になってしまう
  • SSLを使うことは盗聴防止には有効でも、Cookieが漏えいしてしまえば同じ問題が発生しうる

例えば、MemcacheStoreを使う場合、上記の(b)の問題はMemcachedからセッション情報を削除することで回避できます。(a)の問題は自動的には回避できません。ただ、サーバーサイドでセッション管理をするようになれば、回避するように実装することはできるでしょう。

CookieStoreだと難しいかもしれません。上記の記事でもふれられていますが、署名や署名の検証にアカウントや有効期限に紐づいた情報を含めることで対処する方法はあるかもしれません。

いずれにせよセキュリティとコストはトレードオフだと思うので、問題点を認識した上で運営しているサービスに応じた実装を進めていくのがいいかと思います。

不完全とはいえ、Railsのバージョンが進むごとにセキュリティ対策も進んでいくので、極力、最新に近づける努力はした方がいいですね。

■ 余談

マクナマラ氏はこの問題への対応状況を調べるため、9万サイトについて追跡調査を実施し、その結果を11月20日のブログで報告した。それによると、ユーザーの情報が暗号化されない古いバージョンのRuby on Railsをいまだに使っているサイトが1897件見つかったという。

http://www.itmedia.co.jp/enterprise/articles/1311/27/news041.html


90000サイトを調べて、古いバージョンが1897件というのは少ないように思います。
体感的にはもっと危険なサイトがありそうなのですが・・・。母数にはRailsじゃないサイトも含まれているのでしょうか。。。

Posted by あかさた
昨日(10/31)、spice lifeの二人の邦明さん(@igaiga555さん、@HolyGrailさん)が主催する勉強会kuniaki.rbに行ってきました。会場は株式会社スマートニュースさん。

まずは、主催のダブル邦明さん、勉強会の運営お疲れさま&ありがとうございました。
また、会場及び飲み物提供の株式会社スマートニュースさん、懇親会の食べ物提供の株式会社spice lifeさん、ありがとうございました。

大変楽しい会でした。会の様子に関しては写真も撮っていたので、後程どなたかがレポートされるかと思います。
私の方はというと、LT枠をいただけたので、以下のお題で発表させていただきました。

mrubyでゲームを書いてみた
http://www.slideshare.net/yousukekuroda/akasata-20131031

久々のLTだったので、デモの真っ最中に銅鑼を喰らう羽目に。次に発表するときはちゃんと練習して行こうと思います。

発表内容の補足


弊社は、ブラウザ上でゲームを作成して共有するサービス「Rmake」(Flash製)を運営しています。マップエディタなど既成のツールと簡易スクリプトエンジンを使って、RPGやノベルを手軽に作って共有することができます。SLGとか作っちゃう猛者もいますが・・・。

ゲームを作成して共有するサイト - Rmake
http://rmake.jp/

ユーザーさんたちには、楽しく使っていただいていますが、既成のツールと簡易スクリプトエンジンでは、作れるゲームにも幅が無いですし、日本のようにスマホや即売会が活発な国では、ブラウザゲームというだけではいまいち広がりがありません。

そこで、PC(即売会向けに)/スマホ/ブラウザに展開可能で、がんばれば市販されているゲームのレベルに近い物が作れるゲームエンジンが欲しいと考えていました。

mrubyを知ったのは去年のことですが、実際に数行のソースコードでアプリに組み込めることを知って、c/c++で大半の処理を書くことで性能と移植性を維持しつつ、ゲームの中核部分をわかりやすいDSLをmrubyで実現することで、楽しく(がんばれば)それなりのレベルのゲーム作成を行うことができるゲームエンジンを実現することができます。

mruby
https://github.com/mruby/mruby

弊社では主に@dycoonが実装していますが、PC(Windows)とAndroidでそれなりに動くようになってきた(iOS/Flash/Macではまだ・・・)ので、ちょろちょろと露出を増やしつつ、先行してさわってくれるユーザーさんを探しつつ、開発に参加してくれる人を探せたらなと考えています。(もちろん、広げていくためにはオープンソースにするとかいろいろ考えられると思うのですが、その辺、まだ何も考えていません。)

開発中のゲームエンジンは以下からダウンロードすることができます。アルファ版ですので、人柱になる勇気のある方はぜひともさわって、アドバイスやらなんやらをいただけるとうれしいです。

Code on Rmake
https://core.rmake.jp/

あと、以下のイベントに参加します。興味のある方は是非いらしてください~。

デジゲー博
http://digigame-expo.org/
日時:2013年11月17日(日) 11:00 ~ 15:00
場所:大田区産業プラザPio 2F小展示ホール

よろしくお願いします。

Posted by あかさた
Wheneverを使ってRubyでcronを設定したときのメモを残しておきます。
春ごろにも仕事で使ったので、備忘録として残しておこうと思ったら忘れてしまって、今頃になってまたcronの設定を仕事でやったので、今度こそはと思い、メモっておきます。

Railsプロジェクトなのでそれを前提に記事を書いています。

Wheneverとは?


Wheneverは、とかく忘れがちなcronの設定をrubyの構文でわかりやすく記述することができます。

いい加減なプロジェクトだと、本番サーバに何となくcronを設定しただけになって、どこを見ればどういうバッチ処理が走っているのか把握しにくいというような場面によく遭遇しました。

Wheneverはただ単にわかりやすいというだけではなく、設定ファイルをバージョン管理システムに登録しておくことで後から読み返すことが容易になり、設定を忘れてしまった場合にも安心です。

設定ファイルを作成する


さっそく使ってみましょう。Gemfileに以下を追記し、bundle updateします。

gem 'whenever', :require => false


プロジェクトのディレクトリに移動して以下のコマンドを実行するとconfig/schedule.rbが生成されます。

wheneverize .


config/schedule.rbをプロジェクトに合わせて書き換えてみましょう。
詳しくはGitHubにあるreadmeを見るとわかりますが、cronの時間設定をrubyの構文で書くことができます。

# 毎分、rails runnerが走ります。
every 1.minutes do
  runner "Hoge.hoge_method()"
end


cron本来の書式や:day、:hourなどを指定することもできます。
Capistranoの特定のロールだけで実行できるタスクを指定するというようなこともできるようです。

実際に設定してみる


以下のコマンドを実行すると、設定内容が出力されます。crontabには書き込まれません。
不都合な点はないか確認すると良いでしょう。

# 設定する内容を出力。crontabには書き込まれません
whenever

# ヘルプでwheneverのオプションを確認する
whenever -h

# 開発環境にする場合は以下のように書く
whenever -s 'environment=development'

# crontabに書き込む場合
whenever -w

# crontabに書き込む(開発環境)
whenever -s 'environment=development' -w


とても楽ですね。

参考




Posted by あかさた
去年末くらいから取り組んでいたのですが、結構いい感じに出来上がったので告知させてください。
スマートフォンのブラウザ上でTシャツをデザインして注文できるウェブサービス「tmix」を開発しました。
サーバーサイドが私でエディタ部分は@dycoonが実装しました。


スマフォ版Tシャツデザインエディタ


■ 経緯

元々tmixは、2009年に始まったPCブラウザ上でTシャツをデザインして注文できるサービス(flash)でした。
このサービスによって、ブラウザ一つで多くの人が手軽にTシャツを作って楽しめるようになりました。
しかし、時代は変わりスマートフォンからのアクセスが4割を占めるようになり、tmixを訪れる多くの方が、tmixを使うことができないという現実に直面していました。

スマフォアプリの全盛期の今、flashのないブラウザで同等のサービスが実現できるか技術的に難しい面もあります。
Eコマースサイトはアプリに移行しにくい問題(決済などの理由)もあり、リッチなブラウザウェブサービスの開発は今後も増え続けるでしょうから、敢えていばらの道に挑んでみることにしました。

PC版とスマフォ版のエディタ


当面はChrome/Firefoxブラウザなどを使えばPCからもさわれるようになっています。ぜひ、さわってみてください。
(そのうちスマフォ/タブレット以外のアクセスはリダイレクトすると思いますが。)

スマートフォン版tmix

■ 仕組み

デザインエディタにはenchant.jsを利用し、サーバーサイドはRuby on Rails 3.2を使っています。
テキストの描画はスマートフォンは回線が弱いことから、フォントをクライアントに転送することはあきらめ、サーバーサイドでImageMagick(freetype)を使って画像を生成して返しています。


サイト上で利用するTシャツデザインのサムネイル画像やTシャツへの印刷画像もサーバーサイドで生成しています。
しかし、大きな画像は即時には生成できない(※)ため、バックエンドジョブキューを独自に開発して、時間のかからない画像生成はオンラインサーバ、時間のかかる画像生成はバックエンドジョブサーバに振り分けています。

※ 印刷に使う画像は3564*5040pixel、数十秒で生成できることもありますが、Amazon EC2のLargeで1 ~ 2分かかる場合もあります。意外にバカにならないのはpngの圧縮にかかる時間です。オプションで結構時間を削れますが、試行錯誤が多少必要でしょう。

インフラはAmazon Web Serviceを使っています。EC2、ELB、S3、Glacier、Route 53、SES、ElastiCache、RDSなどを使っています。
便利すぎてAWSが無いと生きていけない体になりそうです。

■ 課題や今後の計画

リリースしたものの、スマフォ版はいくつかの技術的な課題を抱えています。
当面は問題を解決しつつ、使い勝手を向上していく予定です。

  • Xperiaの標準ブラウザで落ちることがある
  • 機種によってはデザインエディタのタップの反応が鈍い(チューニングすれば改善できることはわかっていますが、まだ手が回ってません)

tmixそのものはPC時代から続く長年の経験によって、SEO、工場生産の仕組み、ユーザーテストを用いた継続的なユーザビリティ向上など、オーダーメイドを伴うEコマース系サービスとしてかなり高いレベルで運用されています。

しかしながら、時代はどんどん進んでおり、ログ解析をベースに統計的アプローチを活用したサービス改善も多くのサービスが取り入れています。

tmixではこうしたアプローチは一部行われていますがまだまだ不十分です。
今のところは、競合でそこまでやっているサービスはないようですが、いずれは当たり前になります。
競合に差をつけ、さらに快適で使いやすいサービスにするためにも、ログ集約基盤としてfluentdを活用しつつ、独自の分析手法を用いたシステムを開発中です。

業務上の機密にかかわる部分は難しいですが、技術的なポイントは共有可能だと思うので、開発が完了したらまたお知らせしたいなと考えています。

■ 参考

ブラウザ上でTシャツをデザイン・注文できるウェブサービス「tmix」の開発に参加した

2009年にPC版をリリースしたときの告知です。この時はFlashでした。
今はスマートフォンですら、HTML+JavaScriptだけでこれだけのことができるのだから、時代は進歩しましたね。

【日本初】tmixが、スマートフォンからオリジナルTシャツを作って購入できるようになりました!!

tmix運営ブログの記事です。日本初!とかって書くとなんか怪しいですね(笑)。

Posted by あかさた
ImageMagick(Ruby 1.9.3/Passenger 4.0.4/Rails 3.2/rmagick 2.3.11/ImageMagick 6.7.9-10)を使って画像処理をしているプロセス(Passenger)が固まってレスポンスを返さない現象が発生していました。

エラーを返すならわかるのですが、プロセスが固まるとなると、フロントにあるHTTPサーバ(Apache/prefork)も応答できずに固まり、リクエストは次々とくるのでプロセスはどんどん増えていくというとても恐ろしいことになります。

■ やったこと

  • ImageMagickをソースからインストール
  • ghostscriptがインストールされていない
    • yumなどのパッケージ管理ツールからImageMagickをインストールすると依存関係でghostscriptがインストールされる(と思う)
  • rmagickでフォントを使ってテキストを描画

■ エラーメッセージ

1回目は、以下のようなエラーが出ます。2回目は無限ループが発生します。

Magick::ImageMagickError (Postscript delegate failed `/tmp/magick-Zb2G2URF': No such file or directory @ error/ps.c/ReadPSImage/833: `(null)')


■ 解決策とまとめ

ググると、ghostscript関連のエラーのようですので、ghostscriptをインストールしたところ、問題は発生しなくなりました。

  • 当たり前のことですが、ソースからインストールする場合は依存関係に注意(他にもfreetypeを入れ忘れたり・・・)
  • 開発サーバでは、本現象は発生せず(開発サーバにはいろいろ入れるので、ghostscriptもすでに入っていた)

ソースからインストールする前に、yum deplistとかで依存関係をチェックすればこういうミスを減らせるかなぁ・・・。

Posted by あかさた