Rails4へのアップグレードを行ったお話 | サイバーエージェント 公式エンジニアブログ
この記事は、CyberAgent エンジニア Advent Calendar 2014 の24日目の記事です。

コミュニティ事業本部の後藤(@shiro166)です。
パシャっとmyペット(以下パシャペ)というサービスのシステム責任者をやっています。
パシャペでは今年の2月にPHP(CodeIgniter)からRuby(Ruby on Rails)へのリプレースを行いました。
リプレースを行った当初はRuby2.0系最新とRails3.2系最新を使用していたのですが、
6月にRubyを2.1へ10月にRailsを4.1へのアップグレードを行いました。

今回はリプレースの際のお話ではなく、
Railsを3.2から4.1へアップグレードした際に行った作業の一部の話になります。

構成

サイバーエージェントでのRailsアプリケーションの基本的な構成は大崎さんが
以前このブログに書いたこちらの記事を参照してください。
パシャペはこの基本的な構成と比べ下記のような若干の違いがあります。
・Queueingに関してresqueではなくsidekiqを採用している
・shardingしたDBが存在している

規模的にはmodel数で50~100くらいです。
またPHP時代の名残りから複合主キーを使用したtableが存在したりとDB周りがARには若干つらめな構成になっています。

strong_parametersの導入

Rails4からattr_accesibleが外部のgemとして切り出されRailsに取り込まれたのがstrong_parametersです。
Rails3.2でも下記のようにGemfileに記述すれば問題なく使用出来ます。
gem 'strong_parameters'
controller側も下記の例のように修正しました。
UsersController < ActionController::Base
def create
User.create(user_params)
end

private
def user_params
params.require(:user).permit(:name, :sex, :age)
end
end

Rails4用のコードにconvert

Rails3 から4に対応したコードへの変換はsynvertというgemを使用しました。
defaultのsnippetsを使用して一部で問題が発生したので、
変更を加えて使用しました。
synvert の基本的な使い方は下記です。
$ gem install synvert
$ synvert -l # snippetの一覧が表示される
$ synvert -r rails/upgrade_3_2_to_4_0 # rails 3.2から4.0へのコードの変換
$ synvert -r rails/upgrade_4_0_to_4_1 # rails 4.0から4.1へのコードの変換

ActiveRecord周りの修正

一部定義されていないmethodがある
Rails4.1では下記の場合にエラーが発生します。
 users = User.limit(10)
 users.pop # NoMethodError
 users.shift # NoMethodError
# to_aを使用することで回避可能
 users = User.limit(10).to_a
 users.pop
 users.shift
conditions がdeprecatedになった
下記のような構文でエラーになるようになりました。
has_many :posts, conditions: '`id` < 100'
こちらはブロックを渡すことで元の動作と同じになります。
has_many :posts, -> { where('`id` < 100') }
model内で#connection使用の場合の修正
数カ所で生のqueryを使用している部分があるのですが
下記のような記述の際にエラーが発生するようになりました。
query = "SELECT ..."
connection.select(query)
下記のような記述でエラーが発生しないようにできます。
query = "SELECT ..."
ActiveRecord::Base.connection.select(query)
slow query
ARで生成されるSQLのqueryでいくつかRails3の時と違うqueryが生成されていた為に
slow queryが発生していたのでRails3と同じqueryが生成されるように修正を行いました。

composite_primary_keysでのAR4.1.6対応

先で述べた通り複合主キーのtableが存在しているので、
その対応の為にcomposite_primary_keysを使用しているのですが、
当時の最新版がRails4.1.6に対応しておらず一部でエラーが発生していました。
commit履歴を見ると4.1.6対応はmergeされていたのでとりあえずbranch ar_4.1.xを指定して動作確認しようとしたらエラーが発生したので
fork > 該当箇所を修正 > pull request
という流れを行いAR4.1.6対応版がリリースされるまではforkしたbranchを指定していました。
その後対応版がreleaseされたのでそちらのversionを指定して使用しています。

RussianDollCachingへの対応

Rails3ではsweeperを使用して対象のrecordに変更があった場合はキャッシュを削除するようにしていたのですが、
sweeperがrails-observersという別gemに切り出されたのでキャッシュのキーにrecordの更新日時を使用することでrecordが更新された場合に自動的に新しいキャッシュを使用するように変更しました。最初から更新日使えばよかった

実際のリリース

実際のリリース時はメンテナンスを挟み行いました。
Rails4への移行時は最小限の変更で済むように
今回説明した修正の中でもRails3でも正常に動作する部分に関してはRails3の状態で事前にリリースをしておきリリース時に出来る限り最小限の変更で確認が少なくてすむように心がけました。

まとめ

今回紹介した内容は実際に行った修正の一部になります。
実際にアップグレードを行ってみての感想はtestがしっかりしていると実際に動作検証した際の不具合もほぼ無くて済んだので安心感がありました。
パフォーマンスに関しては若干の低下がありましたが、想定の範囲内でした。
Ruby界隈では新しいversionが公開されるサイクルが早く追うのが大変ですが
個人的にはそれが楽しかったりしています。

Rails4.2がリリースされ、Ruby2.2のリリースも間もなくのようでRubyistの皆さんは楽しみですね。パシャペでも順次対応していこうと考えています。

おまけ

Rails4.2がリリースしたのでパシャペの開発環境をRails4.2にして遊んでみました。 おまけなので説明は省きます。(軽く動作確認を行った程度です)
まずはGemfile修正
gem 'rails', '4.2.0'
gem 'composite_primary_keys', git: 'https://github.com/composite-primary-keys/composite_primary_keys', branch: 'ar_4.2.x'
gem 'responders', '~> 2.0'
gemを更新する
$ bundle update
rails serverを起動(vm上で動作してます)
$ rails s -b 0.0.0.0
上記の作業で移行が完了してとりあえず閲覧出来る程度にはなりました。 testを実行するとDEPRECATION WARNINGが大量に出力されていたのといくつかのtestが失敗していたので 実際に移行する際はそこら辺の修正やその他の検証が必要になるかと思います。