JOBLISTで使っているrubyとrailsのバージョンがRuby 2.3.1、Rails 4.2.6とけっこう古くなっていたので、最近、エイヤとアップデートしました。
やったこととか対応したエラーなどをざっとメモっておきます。
作業は以下のように少しずつ進めました。
- Rails 4.2.6 -> 4.2.8。合わせて全体的にgemのバージョンアップ
- Rails 4.2.8 -> 5.0.3
- Ruby 2.3.0 -> 2.4.1
- Rails 5.0.3 -> 5.1.1
Rails 4.2.6 -> 4.2.8
まずはrailsを4系の最新版にアップデート。
合わせて全体的にgemのバージョンアップしました。
bundle update # Gemfile # gem 'rails', '4.2.8' bundle update rails
エラー対応など
railsは特に問題なく動きましたが、他のgemがいろいろおかしくなったので調整しました。
rubocop、haml-lint
追加された新しいルールについて取捨選択&調整しました。
rubocopはauto-correctオプションでだいたい自動修正できるんですが、haml-lintは全部手動なのでけっこう辛かったです。
jquery-ui-rails
requireするパスがかわっていたので修正しました。
# Sprockets::FileNotFound - couldn't find file 'jquery-ui/dialog' with type 'application/javascript': # app/assets/javascripts/application.js -//= require jquery-ui/sortable +//= require jquery-ui/widgets/sortable
CarrierWave
CarrierWave::Storage::Fogがが明示的にrequireしないと見つからなくなっていました。
# uninitialized constant CarrierWave::Storage::Fog (NameError) # config/initializers/carrierwave.rb + require 'carrierwave/storage/abstract' + require 'carrierwave/storage/file' + require 'carrierwave/storage/fog'
set_content_typeは不要になったらしいので削除しました。
# uninitialized constant CarrierWave::MimeTypes # 各種Uploader - process :set_content_type
slack-notifier
channelの指定のしかたがちょっと変わってました。
# NameError: undefined local variable or method `channel' for main:Object - notifier = Slack::Notifier.new ENV['SLACK_WEBHOOK_URL'] - notifier.channel = channel + notifier = Slack::Notifier.new ENV['SLACK_WEBHOOK_URL'], channel: channel
draper
def latitude - source.latitude.to_f + object.latitude.to_f end
Rails 4.2.8 -> 5.0.3
Railsを5.0にアップデートしました。
Rails アップグレードガイドなど見ながら以下の手順で作業しました。
bundle update rails
bundle update railsをがんばって成功させます。
railtiesの依存関係でコケるものが多いです。
Bundler could not find compatible versions for gem "railties": In Gemfile: rspec-rails was resolved to 3.6.0, which depends on railties (>= 3.0)
コケたものは基本的にはいっしょにバージョンアップしてやります。
bundle update rails rspec-rails
しかしそもそもgemが更新されてないものもあります。
https://rubygems.org などで検索して最新版が対応してないものは諦めて、使わないようにするか、パッチ作ります。
rails app:update
実行すると各種コンフィグが上書きされるのでdiff見ながら調整します。
明示的に調整していたもの以外のデフォルト値変更は基本的に全て適用しました。
新しい項目で調整したものはこのあたりです。
# config/application.rb + config.active_record.time_zone_aware_types = %i[datetime time] # config/environments/production.rb # これをtrueにしないとproductionでautoloadがきかなくなっていた + config.enable_dependency_loading = true # DEPRECATION WARNING: `config.serve_static_files` is deprecated and will be removed in Rails 5.1. # Please use `config.public_file_server.enabled = false` instead. # config/environments/xxx.rb - config.serve_static_files = ENV['RAILS_SERVE_STATIC_FILES'].present? + config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
エラー修正、deplicated対応
あとはテスト通るまでエラーを修正していきます。
deplicated対応はパッと出来そうなものだけいっしょに対応して、あとは別対応にしたり5.1アップデート時にまわしたりしました。
record_tag_helper
div_for、content_tag_forはrecord_tag_helperというgemに分離されたようです。
# NoMethodError - The `div_for` method has been removed from Rails. To continue using it, add the `record_tag_helper` gem to your Gemfile: # gem 'record_tag_helper', '~> 1.0' # Gemfile +gem 'record_tag_helper'
年月日がhiddenでそのまま渡せなくなった
パラメータを確認すると文字列として認識されています。
"birthday"=>"{1=>2017, 2=>5, 3=>22}"
記述を調整するとちゃんと渡せました。
- = f.hidden_field :birthday + = hidden_field_tag "entry[birthday]", @entry.birthday
render text
render :text
が非推奨になったようです。
S3に保存したHTMLをそのまま表示するというへんな箇所を修正。
- render text: html + render html: html.html_safe
uniq -> distinct
ActiveRecord::Relationのuniqはdistinctになりました。
# DEPRECATION WARNING: uniq is deprecated and will be removed from Rails 5.1 (use distinct instead). - .uniq + .distinct
where_valuesが使えなくなった
複雑なOR条件などで使っていたwhere_valuesが使えなくなっていました。
rails 5で追加されたorを使うように書き換えました。
ApplicationRecord
各種モデルはActiveRecord::BaseではなくApplicationRecordを継承するようにとのこと。
rails app:updateでは自動作成されませんでしたがせっかくなので手動で対応しておきます。
class ApplicationRecord < ActiveRecord::Base self.abstract_class = true end
- class City < ActiveRecord::Base + class City < ApplicationRecord
sql_mode: TRADITIONAL
group byしたカラムをselectで使っていないものがエラーになるようになりました。
そもそもSQLなおすべきですが、いったん設定調整してエラーにならないようにしました。
# ActiveRecord::StatementInvalid - Mysql2::Error: Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'joblist_devlopment.jobs.id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by: ... # config/database.yml + variables: + sql_mode: TRADITIONAL
enumのカラムから数値を取り出す方法が変わった
こういうモデルがあった時に、
class Job enum status: %i[draft published] end
以前はオブジェクトにカラム名を指定した[]
アクセスをすると数値が取り出せていましたが、
> job[:status] => 1
Rails 5からは文字列を返すようになりました。
> job[:status] => "published"
数値を取り出すには以下のどちらかの方法が必要です。
> job.status_before_type_cast => 1 > Job.statuses[job.status] => 1
request specのdeplication warning
引数の渡し方がキーワード引数になったようです。
# DEPRECATION WARNING: ActionDispatch::IntegrationTest # HTTP request methods will accept only the following # keyword arguments in future Rails versions: # params, headers, env, xhr, as - get url, params, headers + get url, params: params, headers: headers
alias_method_chainがdeplicated
Module#prepend
使うように修正しました。
バージョンアップできないgemを削除
jquery-cookie-rails, readmorejs-railsはrails 5に対応してませんでした。
直接ファイルを設置してgemを使わないように調整しました。
JSライブラリをgem化したものはどんどん動かなくなっているし、ファイル直接おくのもけっこうつらいので、npm的な仕組みに移行したいです。
riby 2.3.0 -> ruby 2.4
rubyをバージョンアップします。
今までサーバ上ではUbuntu 16.04の標準パッケージのrubyを使っていたので、rbenvを使うようにしました。
これは今回の話とはあまり関係がないので割愛します。
細かいところでいくつか問題がおこったので調整しました。
Ubuntu 16.04のtzinfo
WerckerのCIで使っているUbuntu 16.04のdockerイメージをビルドし直すと、タイムゾーンを日本語に設定するところで、
FROM ubuntu:16.04 RUN cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \ echo 'Asia/Tokyo' > /etc/timezone && date
以下のエラーが出るようになってました。
cp: cannot stat '/usr/share/zoneinfo/Asia/Tokyo': No such file or directory
いつのまにかUbuntu 16.04のイメージでタイムゾーンファイルがデフォルトでインストールされなくなっていたのかな?
tzinfoをインストールするようにしました。
FROM ubuntu:16.04 RUN apt-get update && \ apt-get install -y tzinfo ... RUN cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \ echo 'Asia/Tokyo' > /etc/timezone && date
別のちゃんとした方法があるかも。
seory -> meta-tags
SEO用のメタタグ設定にseoryというgemを使っていたのですが、こういうエラーが出るようになってました。
FATAL -- : ActionView::Template::Error (wrong argument type PrefecturesController (expected Regexp)):
ruby2.4で追加されたmatch?
メソッドの影響でこのあたりの挙動がおかしくなっているっぽいですが、
https://github.com/esminc/seory/blob/master/lib/seory/condition.rb#L13
メンテされてなさそうなのでmeta-tagsに移行しました。
Rails 5.0.3 -> 5.1.1
基本的な手順は5.0へのアップデート時と同じです。
app:update後の対応箇所だけいくつかあげておきます。
redis-session-store
動かなくなっていました・・・ メンテ止まってそうなので他のgemに移行したいところですが、いったんこのissueを参考にパッチあてたレポジトリを作成して5.1に対応しました。
# Gemfile - gem 'redis-session-store' + gem 'redis-session-store', github: 'rista-inc/redis-session-store' # rails 5.1対応用のfork
belongs_to optional: true
5系からデフォルトでbelongs_toのカラムはrequiredになっていたので、このタイミングで対応しました。
Rails.application.config.active_record.belongs_to_required_by_default = true
今まで明示的にrequiredなどを記載していなかったので、requiredではないところにだけoptional: true
を追加しました。
- belongs_to :company + belongs_to :company, optional: true
validate false
belongs_toの件で、一部のデータ作成順序を考慮していないテストデータ作成バッチでvalidateがコケるようになってしまったので、一時的にvalidate無効化しました。
- photo.save! + photo.save!(validate: false) - City.import(batch) + City.import(batch, validate: false)
i18nのrequiredエラー
同じくbelongs_toの件で、エラー時のメッセージが無かったので追加しました。
# config/locales/ja.yml + required: を入力してください
rails sがこける
--bind 0.0.0.0
つけるとコケる。
air:joblist mikeda$ bin/rails s --bind 0.0.0.0 /Users/mikeda/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/thor-0.19.4/lib/thor/base.rb:484:in `handle_argument_error': ERROR: "rails server" was called with arguments ["0.0.0.0"] (Thor::InvocationError) Usage: "rails server [puma, thin etc] [options]"
いつのまにか動かなくなっていたけどまだそんなに困ってないので未対応。
対応したら追記します。
gem listen
# これなんかデフォルトで有効になった以下の設定で必要っぽい # config.file_watcher = ActiveSupport::EventedFileUpdateChecker # developmentだけなのであんまちゃんと調べてない # Gemfile + gem 'listen'
まとめ
特に大きな問題は起こりませんでしたが、まとめてやるのやっぱしんどいので、もっとこまめにアップデートするようにします。
あとjsライブラリのバージョン管理をなんとかしよう。