Rails 4.0.0がリリースされたので今参加しているプロジェクトのアプリのアップデートが出来るかを試してみました。
やってみた結果としては、2.3 -> 3.0や、3.0 -> 3.1に比べると大分楽にバージョンアップできる感じです。
たまたま今のプロジェクトで引っかかった問題について、メモがてらまとめておきます。
rake rails:update
diffを見ながらconfigファイルを書き換える。
そんなに大きな変更は無い。
rails4からはinitializerに色々移せって感じで、application.rbが軽量化されてるけど、元のままでも別に問題無い。
設定項目の重複だけ注意。
strong_parameters
元々、gemで先行導入して取り入れていたので概ね問題無く移行できました。
attr_accesibleを利用したセキュリティ対策は、外部のgemに分離されているため、
config.active_record.whitelist_attributes = false
が残っていると警告されます。
attr_accesibleを使いたい場合は、protected_attributesというgemで対応できますが、素直にstrong_parametersに移行する方が良いんじゃないでしょうか。
気を付けておきたいのはdeviseです。
deviseのカスタムコントローラー等を利用していると、strong_parametersの対応を忘れてしまって、いきなりログインできなくなったり、ユーザー登録出来なくなったりします。
というか私は、いきなりテストが落ちてしばらく悩みましたw
後、rails_adminはとりあえず大丈夫でした。
ActiveRecordの関連の記述方法
has_many等の関連は、conditionsというオプションでベースとなるレコードの情報を利用して条件指定を追加できる機能がありましたが、deprecatedになっています。
こんな感じで書けって事らしい。
# before
has_many :comments, conditions: ->(record) { ["comments.writer_id = ?", record.owner_id] }
# after
has_many :comments, ->(record) { where(writer_id: record.owner_id) }
ActiveRecordのfinderメソッドとSunspot
SunspotというSolrから検索した結果とActiveRecordを連携させるgemを利用しています。
Rails4で動作こそしますが、内部でscoped
を利用しているため、deprecatedがガンガン出ます。
Rails4からはall
を使うのが正しいですね。
現時点(2013/7/8)でpull requestは既に上がっていますが、まだマージされていないので、ちゃんと直るのはもうちょっと先じゃないかな。
わざわざフォークするのも面倒だし、様子見中です。
ActiveRecordのincludesで読み込んだ関連の値を利用するためのreferencesメソッド
今まで以下のような感じでincludesでeager loadingした関連レコードの値をメソッドチェインで利用して、検索条件に含める事ができました。
Comment.includes(:post).where("posts.published = ?", true)
4.0.0ではこの記述はdeprecatedとなり、includesで読み込んだレコードの値を利用したい時は明示的にreferencesを呼ぶようになりました。
Comment.includes(:post).where("posts.published = ?", true).references(:posts)
以前のままだとSQLのパーサー書くのが大変になるかららしいです。
ちょっと面倒な気がする。
これの影響で、Sunspotでまたdeprecatedが出ます。
## find_by_xxxメソッド無くなった (ぐあっと書いたら嘘書いてたので修正)
これは、一切使ってなかったので問題無し。
find_all_by_xxxとかがdeprecatedになった。
これは、一切使ってなかったので問題無し。
find_by
を使うようにする。
rspecでトランザクションが上手く動かない
rspecとdatabase_cleanerを利用しているのですが、トランザクションのロールバックを期待して記述していたテストケースが急に落ちるようになりました。
どうもfixtureの読み込み処理が修正されたのが原因らしいです。
rspec v2.14
database_cleaner githubのmaster
を利用していますが、詳細まで追っかけてないので詳しくは不明です。
どなたかご存知でしたら解決策を教えてください…。
追記 (2013/7/9)
@yuki24 さんのコメントを受けて、再現するテストケースとログを用意してみました。
データベースはmysql2です。
v4.0.0: https://github.com/joker1007/transaction_test
v3.2.13: https://github.com/joker1007/transaction_test3
4.0.0 のtest.log
[1m[36mActiveRecord::SchemaMigration Load (0.2ms)[0m [1mSELECT `schema_migrations`.* FROM `schema_migrations`[0m
[1m[35m (0.2ms)[0m SELECT @@FOREIGN_KEY_CHECKS
[1m[36m (0.1ms)[0m [1mSET FOREIGN_KEY_CHECKS = 0[0m
[1m[35m (0.1ms)[0m SELECT DATABASE() as db
[1m[36m (0.3ms)[0m [1mselect table_name from information_schema.views where table_schema = 'transaction_test_test'[0m
[1m[35m (5.2ms)[0m TRUNCATE TABLE `posts`;
[1m[36m (0.1ms)[0m [1mSET FOREIGN_KEY_CHECKS = 1[0m
[1m[35m (0.1ms)[0m BEGIN
[1m[36m (0.1ms)[0m [1mCOMMIT[0m
[1m[35m (0.0ms)[0m BEGIN
[1m[36m (0.2ms)[0m [1mSELECT COUNT(*) FROM `posts`[0m
[1m[35mSQL (0.2ms)[0m INSERT INTO `posts` (`created_at`, `title`, `updated_at`) VALUES ('2013-07-09 05:08:29', 'title0', '2013-07-09 05:08:29')
[1m[36mSQL (0.1ms)[0m [1mINSERT INTO `posts` (`created_at`, `title`, `updated_at`) VALUES ('2013-07-09 05:08:29', 'title1', '2013-07-09 05:08:29')[0m
[1m[35mSQL (0.1ms)[0m INSERT INTO `posts` (`created_at`, `title`, `updated_at`) VALUES ('2013-07-09 05:08:29', 'title2', '2013-07-09 05:08:29')
[1m[36m (0.1ms)[0m [1mSELECT COUNT(*) FROM `posts`[0m
[1m[35m (0.8ms)[0m ROLLBACK
3.2.13 のtest.log
Connecting to database specified by database.yml
[1m[36m (0.1ms)[0m [1mSELECT @@FOREIGN_KEY_CHECKS[0m
[1m[35m (0.1ms)[0m SET FOREIGN_KEY_CHECKS = 0
[1m[36m (0.1ms)[0m [1mSELECT DATABASE() as db[0m
[1m[35m (0.2ms)[0m select table_name from information_schema.views where table_schema = 'transaction_test3_test'
[1m[36m (5.7ms)[0m [1mTRUNCATE TABLE `posts`;[0m
[1m[35m (0.1ms)[0m SET FOREIGN_KEY_CHECKS = 1
[1m[36m (0.1ms)[0m [1mBEGIN[0m
[1m[35m (0.1ms)[0m SAVEPOINT active_record_1
[1m[36m (0.1ms)[0m [1mRELEASE SAVEPOINT active_record_1[0m
[1m[35m (0.0ms)[0m BEGIN
[1m[36m (0.1ms)[0m [1mSELECT COUNT(*) FROM `posts` [0m
[1m[35m (0.1ms)[0m SAVEPOINT active_record_2
[1m[36mSQL (0.1ms)[0m [1mINSERT INTO `posts` (`created_at`, `title`, `updated_at`) VALUES ('2013-07-09 05:07:08', 'title0', '2013-07-09 05:07:08')[0m
[1m[35mSQL (0.2ms)[0m INSERT INTO `posts` (`created_at`, `title`, `updated_at`) VALUES ('2013-07-09 05:07:08', 'title1', '2013-07-09 05:07:08')
[1m[36mSQL (0.1ms)[0m [1mINSERT INTO `posts` (`created_at`, `title`, `updated_at`) VALUES ('2013-07-09 05:07:08', 'title2', '2013-07-09 05:07:08')[0m
[1m[35m (0.1ms)[0m ROLLBACK TO SAVEPOINT active_record_2
[1m[36m (0.1ms)[0m [1mSELECT COUNT(*) FROM `posts` [0m
[1m[35m (0.7ms)[0m ROLLBACK
[1m[36m (0.1ms)[0m [1mROLLBACK[0m
色々試してみた所、DatabaseCleaner.strategy
が:truncation
だと4.0.0でも正常に終了するようです。
:trunsaction
時はsavepointを利用する事でARのtransactionを実現していた部分が、4.0.0で呼ばれなくなってる事が、期待通りの結果にならない理由のようです。
引っかかった点といえば、こんな所です。