4.0のRC1が発表されました。4にアップグレードし、動作確認をして、見つけたバグを報告してみてはいかがでしょうか。3.2のアプリケーションをアップグレードする方法に焦点をあてます。することによって、自分のアプリケーションを使って順を追って理解することができるでしょう。3.2の最新バージョンで動作していること、アプリケーションのgemがすべて最新版であることを確認します。1.9.3以降が必要です。合わせてアップグレード作業の前に、アプリケーションのテストスイートがすべてパスすることを確認しておくのがいいでしょう。自動化されたテストがない場合、マニュアルでのテストが必要になるので作業はより難しくなるでしょう。少なくとも、作業を始める前に何らかの統合テストを追加しておくことをおすすめします。4へのアップグレード作業を進めることにします。これは独立したブランチで行うほうがいいので、ここで作成します。(あるいは現在の最新バージョン)にアップグレードします。他のいくつかのgem(assetsグループ内のものも含む)についてもバージョン番号を変更する必要があります。4はこのグループを削除するので、ここでもそれを削除してそこにあったgemをすべてのグループに含めます。4のデフォルト設定では、production環境は動的にアセットを生成しようとはせず、事前にコンパイルされた静的なアセットを使用するので、この変更に合わせるために、アセットはproduction環境では事前にプリコンパイルされます。assets:compileを実行する場合は、その前に環境をproductionに設定します。assets:precompileこの変更によるプラスの副作用として、アプリケーションの設定ファイルが単純化されます。groupに一致したgemをロードする必要がありましたが、それはdevelopmentとtestの環境だけでした。Rails.env)endを次のように書き換えることができます。groupの指定が必要な場合は、自分でその記述を追加してこのファイルでグループの読み込みの振る舞いをカスタマイズします。updateを実行して新バージョンをインストールしてみます。これはうまくいくように見えますが、このコマンドは時々予想しない振る舞いをする場合があります。outdatedを実行します。知られていないコマンドですが、古くなったgemを探すときに便利です。1.6.4)今回のアプリケーションに対してこれを実行すると、バージョンが古いgemが2つ見つかります。builderのバージョンは少し古く、paper_trailがかなり古い状態です。4と互換性のある新しいバージョンをみつけられないというメッセージの理由がこれです。これが、Gemfileが許容するバージョンについて厳密であるべき理由の一つです。Gemfileではpaper_trailのバージョンを指定していなかったので、ここでそれを指定します。updateを実行すると、バージョンの衝突に関するエラーが発生します。4で動作する別のバージョンを探さなくてはいけません。branchがあるのでそれをGemfileで使用できます。trackerで状態を確認する必要があります。updateを実行すると、PapertrailのGithubプロジェクトにあるバージョンが取得されてアップデートは成功します。これでgemがすべて最新版になったのでspecを実行してみます。その結果は悲惨なものです。EpisodesControllerのcaches_pageメソッドが未定義とあります。cachingを使用しているからです。attributes、ActiveResourceなどが削除されました。救いとしては、これらの機能が必要な場合は、gemを使って簡単に追加することができます。使ったほうがいいものについて、アップグレードの過程でいくつか追加します。4から除かれた機能に関連するエラーが出なくなります。今回のようなメジャーバージョンのアップグレードを行う場合は、できるだけ早くアプリケーションを動作する状態にすることが大事なので、大規模なリファクタリングやその他の大きな変更は避けるべきで、そのためにはこれらのgemを追加するのが便利です。テストがパスしたら、そこから初めてコードを整理して、できるのならこれらのgemに依存しないように変更するのがいいでしょう。bundleコマンドでこれらのgemをインストールし、再度specを実行してパスするか確認します。warningと一緒に、routeに関連したエラーが表示されます。"controller#action"...matchメソッドは受け付けられなくなりました。通常であれば単純にこれをgetに置き換えればいいのですが、複数のメソッドをサポートしたい場合はそれらを追加するかvia:オプションを付けてmatchを使用します。'episodes#new'specを実行すると、多くのテストが落ちます。assignmentに関するもので、その中にはPapertrailのVersionモデルのものも含まれています。attributesを使用しています。この問題を回避するには、アプリケーションの設定ファイルを修正して、active_record.whitelist_attributesの設定をfalseにします。parameterを使用しているアプリケーションの移行のためこれには当たりません。warningがあります。これらを個別に確認して、分類してみましょう。多くはwhiny_nilsなどの設定オプションに関連していますが、それらは必要ではなくなりました。developmentの設定ファイルでwhiny_nilsに関連する行を削除し、eager_loadオプションを追加してfalseに設定します。その他の必要なくなったオプションも同じく削除します。trueend次にproduction環境の設定を行ないます。loadingを有効にし、config.assets.compressオプションを変更します。loadingをfalseに設定します。parameterに移行するので、mass_assignment_sanitizerは削除します。pipelineについて、一つ注意点があります。アプリケーションの設定ファイルを見ると、config.assets.versionオプションがtrueに設定されて残っています。pipelineがデフォルト設定で有効になるのでこれは必要ありません。pipelineを使わないのであればこれをfalseに設定します。使う場合はこのオプションを削除するだけです。initializerです。4ではこのファイルの設定オプションが、secret_tokenからsecret_key_baseに名前が変わりました。3からの移行中には両方のオプションを指定する必要がありますが、アプリケーションの移行が成功したらsecret_tokenオプションは削除できます。secret_key_baseには違うトークンを使う方がいいでしょう。'xx762a2f23950e306261908d4e5519ffe71ce626b119e9fc03a012ba86f46d82ef32d72f283633bacc2f59cf94ce5968552fe97d157e7f00560c1217d4592dda09'これが必要な理由は、クライアント側に保存されているシリアライズされたcookieを暗号化されたcookieに移行させるからです。これによってユーザがセッションクッキーの内容を簡単に見えるのを防ぎます。ここでは多くの設定の変更を行ないましたが、これで全てではありません。4アプリケーションを新規作成し、生成された設定ファイルを見て、現在アップグレード中のアプリケーションと比較して、さらにコピーしなくてはいけない部分がないかをチェックします。これらの変更が済んだところで再度specを実行して、どこかを壊していないか、またdeprecationエラーの数が減ったかどうかを確認します。warningが出るので、これらを減らすことができるのかどうか見てみます。警告の一つは、Episodeモデルの中で発生しています。名前付きスコープを定義したときはいつも、次の例のlambdaのような、呼び出し可能なオブジェクトを2つ目のオブジェクトとして渡すようになりました。time)を含んで設定することが簡単になるからです。lambdaを使わなければクラスがロードされたときの時間が使用されますが、今回の変更によって毎回scopeが呼び出されたときの時間が使用されることになります。発生しているその他のdeprecationが、EpisodesControllerのindexアクションの中にあります。Episode.published.find_all_by_pro(false)endこのような動的なfinderメソッドはサポートされなくなりました。その代わりに、findメソッドを使ってオプションとしてフィールドを渡します。warningも出ません。parameterのようなその他の移行作業に集中することができます。assignmentの制限を移動させて、attr_accessibleを使う代わりにコントローラで制限をかけます。Episodeモデルから属性を削除します。:timecodeコントローラでepisode_paramsというprivateメソッドを定義します。これは従来からのやり方ですが、その他の方法もあります。:timecode)endこのメソッドでは、渡されたパラメータに対してpermitを呼び出して、それに対してpermitされたパラメータを渡します。params[:episode]の代わりにparams.require(:episode)を使って、パラメータのhashが存在することを保証することで、なかった場合にnilの例外が発生することを防ぎます。フォームからパラメータを取得するときにはいつでもこのメソッドを呼び出すことができます。合わせてアプリケーションの設定ファイルから、config.active_record.whitelist_attributesなどの関連する設定オプションを削除します。アプリケーションから移行関連のgemの一つをなんとか削除することができましたが、その他のものを削除するのは簡単ではないかもしれません。rails-observersの代わりにcallbackを使うことができます。page_cachingはまだ役に立つ場面があるので使い続けることにします。cachingについてはエピソード321で紹介しましたが、action_cachingの置き換えに適しています。4.0では依存関係にあるので削除できます。4.1からは削除される予定です。最後にいくつかの修正すべき部分について触れておきます。コントローラでは、before_filterがbefore_actionに変わりました。warningは出ませんが、新しい名前の方が多少意味がわかりやすいでしょう。routesファイルでは、putを使っていた部分は代わりにpatchを使います。このほうがレコードの更新という実態には合っています。4アプリケーションを見て変更点を確認することをお勧めします。/vendor/pluginsはなくなったので、プラグインはgemに置き換えるか/libに移動します。4の機能はまだ多くありますが、それらについては過去のエピソードで紹介しました。RC公開に関するブログ記事の中にもいくつかの情報源が挙げられているので参照してください。