Rails4系で動いているサービスをRails5にバージョンアップする機会があったので、その時に実施した手順や調べた内容をまとめてみた。
注意:
Rspecなどのテスト関連についてはこの記事では扱ってないです。
勉強会で使用した内容を組み合わせて書いているので、かなり箇条書きになってます。
#Rails 5の概要
- 2016年7月ごろに正式リリース
- RailsGuide 日本語版
- Action Cable等の新機能
- Ruby 2.2.2以上で動作
- 内部的に大きな変更が色々
#Rails 5の主な変更点
-
フレームワークのAPIはほとんどRails4と同じ
- Rails 4の知識の大半はRails5で活かせそう
-
Ruby 2.2.2以上が必須(Rails 4は1.9.3以上)
- 基本的には最新版を使用
-
railsコマンド
Rails4.x系で使用していたrakeコマンドはrailsコマンドで代用できるようになった。
$ bin/rails db:migrate # bin/rake db:migrate
$ bin/rails test # bin/rake test
$ bin/rails restart # touch tmp/restart.txt
$ bin/update # bundle install, db:migrate等を実行
- belongs_toの参照先がnilの場合はバリデーションエラーになる
validates :model, presence: true # デフォルト
この挙動は以下のconfig/initializers/new_framework_defaults.rb
を変更することでRails4.x系に戻すことができる。
Rails.application.config.active_record.belongs_to_required_by_default = true
新規作成時には注意する。
アップグレードの場合はデフォルトでfalseになっている。
-
ActiveRecord
のモデルがApplicationRecord
から継承されるようになった
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
end
アプリケーションのモデル全体に機能を追加したい場合はApplication Record
にメソッドを追加する。
-
ActiveJob
のジョブがApplicationJob
から継承されるようになった
class ApplicationJob < ActiveJob::Base
end
-
ActionMailer
がApplicationMailer
から継承されるようになった
class ApplicationMailer < ActionMailer::Base
default from: 'from@example.com'
layout 'mailer'
end
-
ActiveRecord
コールバックの止め方
before_save :ensure_admin
def ensure_admin
throw(:abort) unless self.admin
end
throw(:abort)
ではなくfalse
だと処理が続行される。
- orメソッド
User.where(name: 'Tom').or(User.where('height > ?', 179))
#=> SELECT * FROM users WHERE name = 'Tom' OR height > 179;
Rails 4では生のSQLを使うかArelを使って実現していた。
-
ActiveRecord
の#saveにtouchオプションが追加
updated_at = article
artile.save!(touch: false)
article.update_at == updated_at
=> true
この例ではarticleデータを更新してもupdate_at
は更新されない。
- migration versioning
マイグレーションファイルに、Railsのどのバージョンで生成されたマイグレーションファイルなのかという情報を付与し、そのバージョン情報によりAPIの挙動を変えるというもの。
class CreateBooks < ActiveRecord::Migration[5.0]
def change
create_table :books do |t|
t.string :name
t.timestamps
end
end
end
[5.0]というマイグレーションファイル作成時のRailsのバージョンが追加される。
- セキュアなトークンを扱うAPIの拡張
- has_secure_token
- ワンタイムトークンの実装
- MySQLの設定を上手くしないと衝突の問題あり
- has_secure_token
class User < ApplicationRecord
has_secure_token :auth_token # カラムを指定
end
>> user = User.new(name: 'Tom')
>> user.save
=> true
>> user.auth_token
=> "fppFh6xAsGfNTiDxzreW283f"
-
rails new
した時のフォルダ構成
.
|-- .gitignore
|-- Gemfile
|-- Gemfile.lock
|-- README.md
|-- Rakefile
|-- app
| |-- assets
| | |-- config
| | | `-- manifest.js
| | |-- images
| | | `-- .keep
| | |-- javascripts
| | | |-- application.js
| | | |-- cable.js
| | | `-- channels
| | | `-- .keep
| | `-- stylesheets
| | `-- application.css
| |-- channels
| | `-- application_cable
| | |-- channel.rb
| | `-- connection.rb
| |-- controllers
| | |-- application_controller.rb
| | `-- concerns
| | `-- .keep
| |-- helpers
| | `-- application_helper.rb
| |-- jobs
| | `-- application_job.rb
| |-- mailers
| | `-- application_mailer.rb
| |-- models
| | |-- application_record.rb
| | `-- concerns
| | `-- .keep
| `-- views
| `-- layouts
| |-- application.html.erb
| |-- mailer.html.erb
| `-- mailer.text.erb
|-- bin
| |-- bundle
| |-- rails
| |-- rake
| |-- setup
| |-- spring
| `-- update
|-- config
| |-- application.rb
| |-- boot.rb
| |-- cable.yml
| |-- database.yml
| |-- environment.rb
| |-- environments
| | |-- development.rb
| | |-- production.rb
| | `-- test.rb
| |-- initializers
| | |-- application_controller_renderer.rb
| | |-- assets.rb
| | |-- backtrace_silencers.rb
| | |-- cookies_serializer.rb
| | |-- filter_parameter_logging.rb
| | |-- inflections.rb
| | |-- mime_types.rb
| | |-- new_framework_defaults.rb
| | |-- session_store.rb
| | `-- wrap_parameters.rb
| |-- locales
| | `-- en.yml
| |-- puma.rb
| |-- routes.rb
| |-- secrets.yml
| `-- spring.rb
|-- config.ru
|-- db
| `-- seeds.rb
|-- lib
| |-- assets
| | `-- .keep
| `-- tasks
| `-- .keep
|-- log
| `-- .keep
|-- public
| |-- 404.html
| |-- 422.html
| |-- 500.html
| |-- apple-touch-icon-precomposed.png
| |-- apple-touch-icon.png
| |-- favicon.ico
| `-- robots.txt
|-- test
| |-- controllers
| | `-- .keep
| |-- fixtures
| | |-- .keep
| | `-- files
| | `-- .keep
| |-- helpers
| | `-- .keep
| |-- integration
| | `-- .keep
| |-- mailers
| | `-- .keep
| |-- models
| | `-- .keep
| `-- test_helper.rb
|-- tmp
| |-- .keep
| `-- cache
| `-- assets
`-- vendor
`-- assets
|-- javascripts
| `-- .keep
`-- stylesheets
`-- .keep
44 directories, 75 files
-
rails new
した時にできるGemfile
source 'https://rubygems.org'
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 5.0.0'
# Use sqlite3 as the database for Active Record
gem 'sqlite3'
# Use Puma as the app server
gem 'puma', '~> 3.0'
# Use SCSS for stylesheets
gem 'sass-rails', '~> 5.0'
# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'
# Use CoffeeScript for .coffee assets and views
gem 'coffee-rails', '~> 4.2'
# See https://github.com/rails/execjs#readme for more supported runtimes
# gem 'therubyracer', platforms: :ruby
# Use jquery as the JavaScript library
gem 'jquery-rails'
# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
gem 'turbolinks', '~> 5'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.5'
# Use Redis adapter to run Action Cable in production
# gem 'redis', '~> 3.0'
# Use ActiveModel has_secure_password
# gem 'bcrypt', '~> 3.1.7'
# Use Capistrano for deployment
# gem 'capistrano-rails', group: :development
group :development, :test do
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
gem 'byebug', platform: :mri
end
group :development do
# Access an IRB console on exception pages or by using <%= console %> anywhere in the code.
gem 'web-console'
gem 'listen', '~> 3.0.5'
# Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
gem 'spring'
gem 'spring-watcher-listen', '~> 2.0.0'
end
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
#Rails 5の主な新機能
##Action Cable
Action Cable はRails 5 に新しく導入されたフレームワークであり、Rails アプリケーションで WebSockets とその他の部分をシームレスに統合します。
通常のRailsアプリケーションと同じスタイル・方法でリアルタイム機能をRubyで書くことができる
- リアルタイムに双方向通信を行う機能
- 内部的にはWebSocketプロトコルを使っている
- サーバー側はRuby、クライアント側はCoffeeScriptで実装
- 用途:チャット、プッシュ通知、オンラインゲーム?
$ bin/rails generate channel chat # コードを生成
##Rails API
APIのみを提供するシンプルなアプリケーションをRailsで簡単に作成できるようになりました。 Twitter APIや GitHub APIのような一般公開APIサーバーはもちろん、カスタムアプリケーション用APIサーバーの作成・公開にも便利です。
$ bin/rails new my_api --api
- Railsを使って、画面がない、Web APIのみのアプリケーションを簡単に作るための仕組み
- formatがjsonになる
- APIのための機能がつくわけではない
- RailsからAPIにとって不要な要素を除くだけ
#Rails5へのアップグレード
-
今回の対象サービス
- Rails 4.2.5
- Ruby 2.0.0
- rvm 1.27
- Passenger
-
アップグレード作業
- 公式ドキュメント見る(ネットで調べる)
- アップグレード用の作業ブランチを作る
- 現状のテストが全部パスすることを確認する
- Rubyのバージョンを最新版にアップグレードする
- テスト関連のgemを最新版にアップグレードする
- Rails 5.0.0にアップグレードする
- Rails 5の書き方に変更する
今回のアップグレードでは3、5はやってない。本当はやるべき。
公式ドキュメント見る(ネットで調べる)
参考にしたもの
- http://tech.grooves.com/entry/2016/07/01/184458
- http://qiita.com/jnchito/items/fa680e104d4bf49ae06f
- http://qiita.com/ryo511/items/2a387df126268fec8c78
アップグレード用の作業ブランチを作る
$ git checkout -b rails-5 origin/rails-5
- いきなりmasterで作業するのは危ないので作業用ブランチを作って最後にマージするようにした
- いつでもROLLBACKできるようにしておく
##Rubyのバージョンを最新版にアップグレードする
今回は2.3.0にした。
- rbenv使っている場合
$ rbenv install 2.3.0
$ rbenv global 2.3.0
$ rbenv rehash
$ ruby -v # 2.3.0
- rvm使っている場合
$ rvm install 2.3.0
$ rvm use 2.3.0
$ ruby -v # 2.3.0
Rails 5.0.0にアップグレードする
- Gemfileを変更
gem 'rails', '5.0.0'
- bundle updateする
$ bundle update rails
$ bin/rails -v # Rails 5.0.0
- 依存関係でエラーが出た場合は関連するgemも一緒に最新版にアップグレードする
- Rails5に対応していないgemがあった場合はwarningが出る
ここで試しにbin/rails server
でサーバーが動くか試したところ動かない・・・
vendor/bundle/ruby/2.3.0/gems/sinatra-1.0/lib/sinatra/showexceptions.rb:1:in `require': cannot load such file -- rack/showexceptions (LoadError)
調査した結果、原因はsinatra
とRails 5
でサポートしているrackのバージョンが違うため?
参考:https://github.com/splitrb/split/issues/354
gem fileを該当箇所を以下に変更
gem 'sinatra', github: 'sinatra/sinatra'
そしてbundle install
すると
$ bin/rails server
=> Booting Puma
=> Rails 5.0.0 application starting in development on http://localhost:3000
=> Run `rails server -h` for more startup options
Puma starting in single mode...
* Version 3.5.2 (ruby 2.3.0-p0), codename: Amateur Raccoon Rocketry
* Min threads: 0, max threads: 16
* Environment: development
* Listening on tcp://localhost:3000
Use Ctrl-C to stop
無事サーバが動いた
- 設定ファイルをアップグレードする
$ bin/rails app:update
conflict config/boot.rb
Overwrite /Users/username/Project/project_name/config/routes.rb? (enter "h" for help) [Ynaqdh] y
force config/routes.rb
既存ファイルを上書きしていいか聞かれるのでここでは全てYesと答える
- 上書きされた差分を
git diff
を確認しながら必要に応じて元に戻す- 地道な作業
-
routes.rb
の設定とか全て消えてるので注意 -
Action Mailer
の設定も上書きされるので注意
ここまででアップグレードは大体終わる。
##Rails 5の書き方に変更する
-
schema.rb
の更新- Rails 5では形式が変わっている
下記コマンドでOK
$ bin/rails db:migrate
-
ApplicationRecord
へ変更-
app/models/application_record.rb
を作成 - 既存モデルの継承元を
ActiveRecord::Base
からApplicationRecord
に変更
-
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
end
class Product < ApplicationRecord
-
ApplicationJob
へ変更-
app/jobs/application_job.rb
を作成 - 既存ジョブの継承元を
ActiveJob::Base
からApplicationJob
に変更 - Modelと同じ感じ
-
-
ApplicationMailer
へ変更-
app/mailers/application_mailer.rb
を作成 - 既存ジョブの継承元を
ActionMailer::Base
からApplicationMailer
に変更 - これもModelと同じ感じ
-
-
ログの
DEPRECATION WARNING
をひたすら修正する- 古いバージョンの書き方をしている箇所で発生
- gemが対応してなくて発生
- Rails 5ではAPIが色々変わっているために発生したりもする
- ログに内容が出るので一つずつ修正していく
以降は動作確認しながら適宜修正
- 動作確認すると特定のページでエラー発生
ActiveRecord::StatementInvalid - Mysql2::Error: Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column
Hoge.all.group("fuga")
テーブルの構成の問題?よくわかってない。。。
やりたいこととしては特定の2カラムに対して、重複を除いたレコードを取得したかったので以下のように変更した。
Hoge.select(:fuga, :piyo).distinct
参考:http://qiita.com/bboobbaa/items/9fdca834076cb4c3389e
##番外編
- 本番デプロイ時にハマったこと
$ rvm use 2.3.0 # ruby 2.3.0を使う
$ git pull
$ bin/update
$ bin/rails restart # これで動くはず!
結果、動かない・・・
Railsのログにも情報がない・・・
Apacheのログを確認すると・・・
Could not find rake-10.4.2 in any of the sources (Bundler::GemNotFound)
???
ruby 2.3.0に切り替えてbundle install
しているのに使われてないような気がする・・・
原因はPassenger
だった
Passenger
はRailsアプリのデプロイツールで、アプリが使用するrubyのデフォルトバージョンを設定でき、これがruby 2.0.0
のままだった。。。
設定ファイルを変更し、Apache再起動で無事デプロイ完了!
所感
- 細かい設定の変更はあるが、一人でもできそう
- エラーが出たらよく内容を読んで頑張る(笑)
- 正式リリース直後は英語のドキュメントが多くて苦労したけど、今は日本語のドキュメントもまとまってる
- Rails 4の知識があればそんなに困らない
- これから勉強するならまず、Rails 4から始めてその後にRails 5にチャレンジするのが良さそう!