LoginSignup
32

More than 5 years have passed since last update.

rails 4.2.8->5.0.2の時に実施した手順メモ

Last updated at Posted at 2017-03-07

5.1.0のbetaがでて、そろそろ4.2もサポート範囲外になりそうなので、4.2から5.0にアップデートすることにしましたので、
色々作業した内容をメモって行きます。

本当は5.1まで一気にあげたい所ですが、まだbetaということで、一旦5.0.2に。
なあに、メジャーバージョンアップに比べればマイナーバージョンアップだし、きっと影響無いに決まってる。(慢心)

Rails 5へのアップグレード手順メモ(Rails 4.2.6 => 5.0.0)を参考に作業

http://qiita.com/ryo511/items/2a387df126268fec8c78 を参照

  • gem のアップデート
  • Rails update
  • ApplicationRecordをActiveRecordのモデルのベースクラスにする

を実施。
rubyは既に2.4に切り替え済み、
ApplicationJobは使ってなかったので放置

gemのアップデート

gemのアップデート時には

Gemfileをまず

gem 'rails', '5.0.2'

に変更してbundle updateをした所、railitesで引っかかった。
一旦引っかかった物を全部コメントアウトしていたが、最終的に

# gem 'quiet_assets'

だけはコメントアウトしっぱなしになった。
同機能がrails5で入った様です。

Rails update

$ bin/rails app:update

rails update時には、実施してその後git diffして色々重要そうな部分を残しました。
config/initializers/assets.rb とか、configに何か独自設定してても削除されるので、ちゃんと残す様にしないといけない。
binの中身もspringが関係なくなるようだったのでを残すように更新した。(その分後述のトラブル発生)

ApplicationRecordをActiveRecordのモデルのベースクラスにする

app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true
end

sed -i -e "s/ActiveRecord::Base/ApplicationRecord/" app/models/*.rb      

srpingの関係で"Array values in the parameter to Gem.paths= are deprecated."が出る

ruby/rails のversionを上げた際に Array values in the parameter to Gem.paths= are deprecated. エラーが出た時 を参考に

bundle exec spring binstub --remove --all
bundle exec spring binstub --all

を実行。
多分、 bin/rails app:update時に、bin以下をsrping絡まない様にしてればエラーは発生しなかった(その場合、spring binstubを実行する必要あり?)

rspec用にGem追加

rsepcをとりあえず単品で動かしたらエラーがでたので警告通りGemを追加

     NoMethodError:
       assert_template has been extracted to a gem. To continue using it,
               add `gem 'rails-controller-testing'` to your Gemfile.
gem 'rails-controller-testing'

rspecのget,postの書き方を変える

getやpost時にパラメータはparams: {}で渡す必要ができた模様

Deprecated style:
get :show, { id: 1 }, nil, { notice: "This is a flash message" }

New keyword style:
get :show, params: { id: 1 }, flash: { notice: "This is a flash message" },
  session: nil # Can safely be omitted.

大雑把に書き換える

sed  -i -r -e 's/(get|post)([^,]*,) ?(.*)/\1\2 params: {\3}/' spec/controllers/**/*_spec.rb
sed -i -r -e 's/\{\{(.*)\}\}/{\1}/' spec/controllers/**/*_spec.rb
grep "{{" spec/**/*_spec.rb | vi - # 色々いじる

適当に置換したのですが、receive(:get_api).and_returnとかやってる所も置換されて偉いことに
後、元々

get :show, parameters 

としてた所が


get :show, params: {parameters}

となったりしてエラーになったのでvimで :%s/params: {([^:]*)}$/params: \1/gc の様なコマンドかけたり、修正が大変でいsた。

routes.rbの:actionがwarningになっていたので修正

routes.rbで以下の様な警告がでたのでここを参考に修正
:actionでそれぞれに割り振るのが警告出るようになったぽい

Using a dynamic :action segment in a route is deprecated and will be removed in Rails 5.2.
config/routes.rb
  # get "users/:action", controller: "users"
  %w(index list).each do | action |
    get "users/#{action}", controller: "users", action: action
  end

before_filter -> before_action に変更

以下の警告がでたので未だにbefore_filterだった所を置換

DEPRECATION WARNING: before_filter is deprecated and will be removed in Rails 5.1. Use before_action instead. 
 sed  -i -r -e 's/before_filter/before_action/'  app/controllers/**/*_controller.rb

gemで使っているライブラリの方のbefore_filterのアラートは残ってる様です……

ActiveRecordのuniq は distinctに

uniqからdistinctになったぽい。
Array#uniqなので同じ名前のが良かったなあ……

DEPRECATION WARNING: uniq is deprecated and will be removed from Rails 5.1 (use distinct instead)
# User.uniq
User.distinct

enumの挙動の違い

rails 4.2から動きが変わっているので、使っている場合は注意。
サンプルとしてrails g model Article status:integer で制作したモデルに対し以下のenumを設定してそれぞれのメソッドの結果

app/models/article.rb
class Article < ActiveRecord::Base
  enum status: {draft: 0, published: 1 }
end
>  article = Article.new(status: :draft)
 => #<Article id: nil, status: 0, created_at: nil, updated_at: nil> # rails 4.2
 => #<Article id: nil, status: "draft", created_at: nil, updated_at: nil> # rails 5.0

> article.status
 => "draft" # rails 4.2
 => "draft" # rails 5.0

> article.attributes["status"]
 => 0 # raisl 4.2
 => "draft" # rails 5.0

# 元の値を取りたい時は _before_type_cast
# article.status_before_type_cast

> Article.where(status: :draft).to_sql
 => "SELECT \"articles\".* FROM \"articles\" WHERE \"articles\".\"status\" = NULL" #=> rails 4.2
 => "SELECT \"articles\".* FROM \"articles\" WHERE \"articles\".\"status\" = 0" #=> rails 5.0

Rails 4.2 で Arel を使って OR クエリを構築するで使ってたorが動かなくなってた

大変お世話になっていたのですが、ORがデフォルトで動く様になっていたので、変更
where_valuesのメソッドがwhere_clauseになってて挙動が変わっていたので、 修正するべきか悩んでいます。
21箇所だし、Rails5以降標準の方法にそれぞれ置換した方が良さそう

Arelでクエリを書くのはやめた方が良い5つの理由(Rails 5.0以前の場合)という話もあり、共感していたのですが、
RailsのorでSQLにカッコつける方法がわからなかったので、or内をグルーピングできる元の方が良いので、バッドノウハウですが、新しく、Rails 5.0.2でArel を使って OR クエリをカッコつけて構築するライブラリにしました。
手探りなので大分かっこ悪い気がします。バージョンが上がると通用しなくなるでしょうし。

config/initializers/active_record_wherechain_or.rb
ActiveRecord::QueryMethods::WhereChain.include(Module.new do
  def or(*scopes)
    where_clause = nil 

    if scopes.size == 1 &&  scopes[0].is_a?(Array)
      scopes = scopes[0]
    end 
    scopes.each do | scope |
      temp_scope = scope.is_a?(Hash) ? @scope.model.where(scope) : scope
      grouping_where_clause = Arel::Nodes::Grouping.new(temp_scope.where_clause.ast)
      if where_clause.nil?
        where_clause  = ActiveRecord::Relation::WhereClause.new([grouping_where_clause], temp_scope.where_clause.binds)
      else
        where_clause  = ActiveRecord::Relation::WhereClause.new([where_clause.ast.or(grouping_where_clause)],
                                                                where_clause.binds + temp_scope.where_clause.binds)
      end 
    end 

    if where_clause
      @scope.where_clause += where_clause
    end 
    @scope
  end 
end)

rspecで空のパラメータがnilになる?

未検証ですが、paramsにからのハッシュを入れていたデータがエラーになっていました。


# テスト側
 get :index, params: {q: { } }

# 本体側 
 if params[:q][:abc_to_eq] #=> undefined method `[]' for nil:NilClass

if文の書き方変えて対処だけしたので、深く掘っていません

render :text でDEPRECATION WARNING:

jsonならrender :json、テキストなら render :plainなど、ちゃんとフォーマットに従って返す様にするべきらしい

warning: constant OpenSSL::Cipher::Cipher is deprecated

deprecatedになっているOpenSSL::Cipher::Cipherの代わりにOpenSSL::Cipherを使用するよう修正しています。

置換 s/OpenSSL::Cipher::Cipher/OpenSSL::Cipher/g

ActiveRecord::Relationに<<できなくなってた

他にしてる人は少なそうですが

users = User.where(admin: true)
users << User.new

こんな感じの事ができなくなってました。
users.to_aしてから<<する様にして回避

rspec の get で Rack::Test::UploadedFileのパラメータがstringになった

本来postで書いておくべきだったテストをgetで書いていたミスがあったのですが、エラーがでて発覚しました。
postに書き換えて対応

jquery-ui系のパスが変更されていたので適応させる

couldn't find file 'jquery-ui/datepicker-ja' with type 'application/javascrip

jquery-ui/widgets/datepicker に
//= require jquery-ui/i18n/datepicker-ja 日本語化にこちらも追加

参考: http://stackoverflow.com/questions/19171470/ruby-on-rails-couldnt-find-file-jquery-ui-datepicker

couldn't find file 'jquery-ui/mouse' with type 'application/javascript'

require jquery-ui/widgets/mouse に

参考: https://github.com/jquery-ui-rails/jquery-ui-rails

link_toやurl_foでparamsを引数にするとエラー

検索条件を保持してリンク先を追加する様に、link_toにparamsを追加してた所がエラーになっていました。

Attempting to generate a URL from non-sanitized request parameters! An attacker can inject malicious data into the generated URL, such as changing the host. Whitelist and sanitize passed parameters to be secure.

参考: http://stackoverflow.com/questions/39152870/rails-5-can-anyone-explain-how-generating-a-url-from-non-sanitized-request-par

permitして、許可するパラメータを指定する

<%= link_to "csvダウンロード", params.permit(:date_at).merge({:format => "csv"}) %>

params[:user]の中身はhashクラスを継承してない。

params[:page] の書き方がDEPRECATION WARNING

DEPRECATION WARNING: Method to_param is deprecated and will be removed in Rails 5.1, as ActionController::Parameters no longer inherits from hash. Using this deprecated behavior exposes potential security problems. If you continue to use this method you may be creating a security vulnerability in your app that can be exploited. Instead, consider using one of these documented methods which are not deprecated: http://api.rubyonrails.org/v5.0.2/classes/ActionController/Parameters.html

許可する場所を用意して、to_hしてアクセスしてみた(許可しないと値が取れないっぽい)

params.permit(:page)
params.to_h[:page]

params.to_unsafe_h[:page]でアクセスさせて対応しました。非推奨っぽいけど一番楽だった。

rspecのパラメータがActionController::Parameters として渡される

rspecがこれまでコントローラーに渡してきたパラメータはhashでしたが、ActionController::Parametersとして渡される様になっており、以下の様なケースでエラーがでてました。

   post :create, record.attributes.merge(body: "")
   # => 4.2 だと {"body" => ""}と言うデータが渡る
   # => 5.0 だと {"body" => 元のデータ} で渡る

そもそもattributesは文字列なのでシンボルでハッシュを渡してるテストコードの書き方自体が適切ではないのですが、
こういったケースでのrspecのエラーもありました

config.logger = Logger.newしていると、cssへのアクセスでエラーが出る

config/environments/development.rb で

config/environments/development.rb
config.logger = ActiveSupport::Logger.new(config.paths["log"].first)

と書いてた事が原因で以下のようなエラーがでていました。

Unexpected error while processing request: super: no superclass method `local_level=' for #Logger:0x007fb77ff27928
Did you mean? local_variables

どうもActiveSupportで拡張時にメソッド追加したのかな?
原因はちゃんと調べてはいません。
ActiveSupport::Loggerにしておくと解決しました。

config/environments/development.rb
 config.logger = ActiveSupport::Logger.new(config.paths["log"].first)

delete_all(conditions)がDEPRECATION WARNING

delete_allの引数に条件ではなく、whereにかく

Account.delete_all(area_id: 48)

ではなく

Account.where(area_id: 48).delete_all

rspec のxhr :get 〜〜と言う書き方がDEPRECATION WARNING

xhrの引数だったのを、引数にxhr: trueを

 # xhr :get, :check, params: {:format => :js, :id => record.id}
 get :check, params: {:format => :js, :id => record.id}, xhr: true

turbolinks 5の書き方が全然違うので、 '=2.5.3'に指定した

turbolinks5にバージョンアップされたのですが、jquery-turbolinksが効かなかった為、

gem 'turbolinks', '=2.5.3'

と指定しました。

params[:q] にhashが入ってる時にlink_toにパラメータを渡しても上手く動かない

ActiveRecordのwhereで配列内の配列はTypeError: can't quote Array

 Article.where(status: [[0], 1])
# Rails 4.2
 DEPRECATION WARNING: Passing a nested array to Active Record finder methods is deprecated and will be removed. Flatten your array before using it for 'IN' conditions. (called from irb_binding at (irb):3)
  Article Load (2.4ms)  SELECT "articles".* FROM "articles" WHERE "articles"."status" IN (0, 1)
 => #<ActiveRecord::Relation []>

# Rails 5.0
TypeError: can't quote Array

発生してからよく見たらDEPRECATION WARNINGと警告されてました。
flattenして修正

submit_tag がデフォルトでボタンを押すとdisableになる

data-disable-withというデータが自動的に登録されていて、クリックするとdisableになって押せなくなる。
config.action_view.automatically_disable_submit_tag = false
で解決する。
参考: http://y-yagi.hatenablog.com/entry/2015/08/18/062346
日本語で調べたRails5.0の変更点には載ってなかった……。

とりあえず、ここまでの作業で、rspecのエラーは0になりました。
間違っている箇所があればご指摘をいただけると助かります。(プロジェクト的にも)

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
32