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 あかさた
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 あかさた
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 あかさた
Rails 4.0.0が出ていたので、3.2.12で動かしているウェブアプリ(このブログ)を4.0.0にアップグレードしてみることにしました。

Rails 4.0: Final version released!
http://weblog.rubyonrails.org/2013/6/25/Rails-4-0-final/

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

coffee-rails、sass-railsも4.0.0にしました。
古いrailtiesに依存していてbundle updateが動かないことがあるためです。

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

bundle update
rake rails:update


以下、rake rails:updateの作業ログです。

  • boot.rbは上書き
  • routes.rbはスキップ
  • application.rb上書き(このアプリに関してはtime_zoneを指定していただけだったので、あとから追記)
  • environment.rb上書き
    • 環境ごとのファイルは適宜マージ
  • initializers/inflections.rb上書き
  • initializers/secret_token.rb上書き
  • initializers/session_store.rb上書き
  • initializers/wrap_parameters.rb上書き
  • locales/en.yml上書き

environment下のマージはいつも面倒・・・。そんなに設定をいじっているわけでもないのですが。

■ ソースコードの修正作業ログ

○ routes.rb

matchがまだ残っていたので、getやpostなどに置き換え。

○ mass-assignment対応

以下のように、controllerでホワイトリスト方式で指定するようになりました。

params.require(:hoge).permit(:attr_1, attr_2)
post_params = params.require(:hoge).permit(:attr_1, attr_2)
hoge = Hoge.new(post_params)


○ ActiveRecordのscopeをlambdaで記述

意外にハマるところなので、注意してください。

○ set_table_nameをself.table_nameに変更

これは3.2でdeprecation warningが出ていたものなのでいまさら感が漂いますが。。。

○ turbolinks

これは有効にしませんでした。。。

■ 雑感

メジャーバージョンアップであることを思えば、割と手軽に上げることができました。
scopeが影響範囲が広いので、テスト書いてないとちょっと怖いですね。


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 あかさた
以下の脆弱性がアナウンスされていたため、本ブログのRailsのアップグレードを実施しました。

JVNVU#94771138 Ruby on Rails に複数の脆弱性
http://jvn.jp/cert/JVNVU94771138/

(1) GemfileのRailsバージョンを変更
(2) route.rb, environments下のファイルを退避(上書きされるため)
(3) 以下のコマンドを実施

bundle update
rake rails:update


特にハマるところもなく終了。

Posted by あかさた
勉強がてら、Bootstrapを使ってブログの見た目を変えてみました。ついでに、Rails 1(!)から3.2に移行しました。

新しい方
http://akasata.com/

古い方
http://www.rmake-labo.com/akasata

見比べると全然違いますが、サイトの構造は、コメント、トラックバックなどのいくつかの機能を無くしたこと以外は変わっていません。BootstrapはレスポンシブWebデザインにも対応していることから、スマフォやタブレットでもそこそこ見えるようになっています。

ちなみに、コードのハイライトはgoogle-code-prettifyを使っています。

基本、はてなブログを使っているので、3年ほど更新していませんでしたが、こちらに乗り換えようかなと検討中。。。

Posted by あかさた