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


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のアップデート](http://qiita.com/ryo511/items/2a387df126268fec8c78#rails%E3%81%AEgem%E3%82%92%E3%82%A2%E3%83%83%E3%83%97%E3%82%B0%E3%83%AC%E3%83%BC%E3%83%89%E3%81%99%E3%82%8B)

gemのアップデート時には

Gemfileをまず

```Gemfile
gem 'rails', '5.0.2'
```

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

```Gemfile
# gem 'quiet_assets'
```

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


# [Rails update](http://qiita.com/ryo511/items/2a387df126268fec8c78#rails-update)

```
$ bin/rails app:update
```

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

# [ApplicationRecordをActiveRecordのモデルのベースクラスにする](http://qiita.com/ryo511/items/2a387df126268fec8c78#applicationrecord%E3%82%92activerecord%E3%81%AE%E3%83%A2%E3%83%87%E3%83%AB%E3%81%AE%E3%83%99%E3%83%BC%E3%82%B9%E3%82%AF%E3%83%A9%E3%82%B9%E3%81%AB%E3%81%99%E3%82%8B)

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

```

```bash
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.　エラーが出た時](http://qiita.com/lulu-ulul/items/f6cdfb02570821c82418) を参考に

```bash
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.
```

```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.
```

大雑把に書き換える

```bash
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とかやってる所も置換されて偉いことに
後、元々


```ruby
get :show, parameters 
```

としてた所が 

```ruby
get :show, params: {parameters}
```

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

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

routes.rbで以下の様な警告がでたので[ここを参考](http://stackoverflow.com/questions/37008713/rails-5-1-routes-dynamic-action-parameters)に修正
:actionでそれぞれに割り振るのが警告出るようになったぽい

```
Using a dynamic :action segment in a route is deprecated and will be removed in Rails 5.2.
```

```ruby: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.　
```


```bash
 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を設定してそれぞれのメソッドの結果

```ruby: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 クエリを構築する](http://qiita.com/QUANON/items/d6772127ffc0e7b78759#-or-%E3%82%AF%E3%82%A8%E3%83%AA%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B%E3%83%9E%E3%83%B3)で使ってたorが動かなくなってた

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

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

```ruby: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にからのハッシュを入れていたデータがエラーになっていました。

```rspec

# テスト側
 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

http://y-yagi.hatenablog.com/?page=1464730394
> deprecatedになっているOpenSSL::Cipher::Cipherの代わりにOpenSSL::Cipherを使用するよう修正しています。

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

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

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

```ruby
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して、許可するパラメータを指定する

```erb
<%= 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として渡される様になっており、以下の様なケースでエラーがでてました。

```ruby
   post :create, record.attributes.merge(body: "")
   # => 4.2 だと {"body" => ""}と言うデータが渡る
   # => 5.0 だと {"body" => 元のデータ} で渡る
```
そもそもattributesは文字列なのでシンボルでハッシュを渡してるテストコードの書き方自体が適切ではないのですが、
こういったケースでのrspecのエラーもありました

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

config/environments/development.rb で

```ruby: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にしておくと解決しました。

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

# delete_all(conditions)がDEPRECATION WARNING

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

```ruby
Account.delete_all(area_id: 48)
```

ではなく

```ruby
Account.where(area_id: 48).delete_all
```

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

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

```ruby 
 # 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が効かなかった為、

```Gemfile
gem 'turbolinks', '=2.5.3'
```

と指定しました。

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

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

```ruby
 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になりました。
間違っている箇所があればご指摘をいただけると助かります。(プロジェクト的にも)