週刊Railsウォッチ(20170519)Rails 5.1.1/5.0.3リリース、RailsでAPIサーバーを作る、HackerNewsでトップになるチャンス?ほか

こんにちは、hachi8833です。fishをそおっとインストールしてみましたがとりあえず元に戻しました。

番外

  • サイエンスライターの森山和道さんの「あれこれ新聞」にTechRacho記事を掲載いただきました。ありがとうございます!

  • パーフェクトRuby(改訂2版)が発売されました。Ruby 2.4対応だそうです。おめでとうございます。早速ポチりました。

早くもRails 5.1.1と5.0.3がリリース(Rails公式ニュースより)

バグフィックスが中心なので急いでインストールする必要はないとのことです。

5.0.2 -> 5.2.35.0.3のコミット
5.1.0 -> 5.1.1のコミット

今回は5.1.1の修正点を中心に追いました。Railsウォッチで取り上げたもの、バージョン変更、スペルミスなどのコミットは省略しました。

#29029: rake -Tでtest環境ではなくdevelopment環境をデフォルトで読み込むよう修正

# railties/lib/rails/test_unit/railtie.rb
 require "rails/test_unit/line_filtering"

  if defined?(Rake.application) && Rake.application.top_level_tasks.grep(/^(default$|test(:|$))/).any?
-   ENV["RAILS_ENV"] ||= "test"
+   ENV["RAILS_ENV"] ||= Rake.application.options.show_tasks ? "development" : "test"
  end

rake -Tそのものは、定義されているrakeタスク一覧を出力します。テスト環境のrakeタスクと知らなかったらはまりそうです。

その場でmorimorihogeさんから、bundle exec rake middlewareでRailsのミドルウェアをリストアップできることを教わりました。「このミドルウェアの読み込み順序が変わると問題が発生することあるんですよ」とのことです。

#29034: Rescuable#rescue_with_handlerで例外の原因チェーン(cause chain)を扱えるよう修正

Ruby 2.4.1だとこの現象を再現できなかったそうです。cause chainという言葉をどう扱おうかと思いましたが、ひとまず「原因チェーン」にしてみました。

# activesupport/lib/active_support/rescuable.rb
-     def rescue_with_handler(exception, object: self)
+      def rescue_with_handler(exception, object: self, visited_exceptions: [])
+        visited_exceptions << exception
+
          if handler = handler_for_rescue(exception, object: object)
            handler.call exception
            exception
          elsif exception
-          rescue_with_handler(exception.cause, object: object)
+          if visited_exceptions.include?(exception.cause)
+            nil
+          else
+            rescue_with_handler(exception.cause, object: object, visited_exceptions: visited_exceptions)
+          end
         end

#29040: ActionController::Parameters#deleteにブロックを渡せるよう再修正

# actionpack/lib/action_controller/metal/strong_parameters.rb
-    def delete(key)
-      convert_value_to_parameters(@parameters.delete(key))
+    def delete(key, &block)
+      convert_value_to_parameters(@parameters.delete(key, &block))
     end

もともと#20868Hash#deleteを継承してブロックを渡せるようになっていたのが、どこかで継承されなくなっていたとのことです。

#29043: FinderMethods#exists?でemptyの場合のeager loadingを抑制

kamipoさんによる#29025の修正です。

# activerecord/lib/active_record/relation/finder_methods.rb
-      return false if !conditions
+      return false if !conditions || limit_value == 0
+
+      relation = self unless eager_loading?
+      relation ||= apply_join_dependency(self, construct_join_dependency(eager_loading: false))

-      relation = apply_join_dependency(self, construct_join_dependency(eager_loading: false))
       return false if ActiveRecord::NullRelation === relation

#28995: Capybaraがマイナーバージョンアップした場合にも追従できるよう変更

2.13.0でロックされてたんですね。

-gem "capybara", "~> 2.13.0"
+gem "capybara", "~> 2.13"

つっつきボイス「これ悩ましい問題だよね」「semantic versioningに対して挙動の違うgemがあるとこうやってハマる」

#29002: テストコードの引数に丸かっこを追加

# activerecord/test/cases/quoting_test.rb
      def test_quote_with_quoted_id
-       assert_deprecated /defined on \S+::QuotedOne at .*quoting_test\.rb:[0-9]/ do
+       assert_deprecated(/defined on \S+::QuotedOne at .*quoting_test\.rb:[0-9]/) do
        assert_equal 1, @quoter.quote(QuotedOne.new)
      end

-       assert_deprecated /defined on \S+::SubQuotedOne\(\S+::QuotedOne\) at .*quoting_test\.rb:[0-9]/ do
+       assert_deprecated(/defined on \S+::SubQuotedOne\(\S+::QuotedOne\) at .*quoting_test\.rb:[0-9]/) do
        assert_equal 1, @quoter.quote(SubQuotedOne.new)
      end
    end

テストのワーニング解消です。その場では「正規表現の開始終了文字/でワーニングが出ていたのかな?」「それともブロックの有無で出るのかな?」という話題どまりでしたが、BPS Webチームのakioさんが翌日再確認したところ、前者の引数の/正規表現/を丸かっこで囲まないことに対してのワーニングでした。

  • //の場合: 「ambiguous first argument; put parentheses or a space even after `/’ operator」
  • (//)の場合: warningなし
  • %r//の場合: warningなし

akioさんいわく「Railsの修正も%r//を使った方がスマートだったかなー」とのことでした。ありがとうございます!

5a6091: テストコードでrubygems 2.6.12を一時的に差し止め

rubygemsのバグですが、原因不明なのでとりあえず2.6.11を使うようにしました。「rubygemsで起きるとはつらいねー」と思わず声が上がりました。

-  - "gem update --system"
+  - "gem update --system 2.6.11"

#28978#28337: Railsガイドのディレクトリパスがおかしいのを修正

ロケールが重複していたのを修正しています。韓国の開発者のようです。

Before:

source_dir: "source/ko/ko"
output_dir: "output"

After:

source_dir: "source/ko"
output_dir: "output/ko"

#28943: rails new-pオプションより環境変数が優先されていたのを修正

         def port
-          ENV.fetch("PORT", options[:port]).to_i
+          options[:port] || ENV.fetch("PORT", DEFAULT_PORT).to_i
         end

ポート番号を環境変数で指定すると-pオプションが効かなくなっていた問題の修正です。

つっつきボイス-pは臨時の指定だからやっぱりこちらが効いてくれないとねー」

#28939:マイグレーションを忘れたときのメッセージを見やすく変更


https://github.com/rails/rails/pull/28939より

マイグレーションを忘れてRailsを起動したりすると表示されていた大量のバックトレースを抑制しました。

つっつきボイス「これにびびった初心者多いだろうねw」

#28941: package.jsonが誤って削除されることがあるのを修正

# railties/lib/rails/generators/rails/app/app_generator.rb
      def create_vendor_files
         build(:vendor)
-
-        if options[:skip_yarn]
-          remove_file "package.json"
-        end
       end

つっつきボイス「Issueタイトルが「Remove unnecessary package.json deletion」なのでdeletionのremoveとかややこしいなー」「コードを見れば一目瞭然だけどね」

#28920: remove_possible_methodrequire漏れだったのを修正

# activesupport/lib/active_support/core_ext/date_time/compatibility.rb
require "active_support/core_ext/date_and_time/compatibility"
+require "active_support/core_ext/module/remove_method"

先週の#28835に続くrequire漏れ修正です。ActiveSupportが巨大なのでなかなか目が届かなさそうです。

Rails: action_controller_baseaction_controller_apiを追加(Rails公式ニュースより)

ここからはいつもの進行です。

ActiveSupportには#run_load_hooksというメソッドがあり、起動時の読み込みを絞り込むのに使われていることを知りました。

このメソッドで指定できるライブラリの中にaction_controllerもありますが、もう少し細かく指定できるようaction_controller_baseaction_controller_apiを追加したということです。

# actionpack/lib/action_controller/api.rb
ActiveSupport.run_load_hooks(:action_controller_api, self)

# actionpack/lib/action_controller/base.rb
ActiveSupport.run_load_hooks(:action_controller_base, self)

Rails: フィクスチャのアクセサメソッドに引数を渡さない場合にすべてのフィクスチャを返すよう変更(#railsnews)より)

# activerecord/lib/active_record/fixtures.rb
...
-              instances.size == 1 ? instances.first : instances
+              return_single_record ? instances.first : instances
...

従来は空の配列[]が返されていました。

Rails: HashWithIndifferentAccessfetch_valuesを実装(Rails公式ニュースより)

# activesupport/lib/active_support/hash_with_indifferent_access.rb
+    def fetch_values(*indices, &block)
+      indices.collect { |key| fetch(key, &block) }
+    end if Hash.method_defined?(:fetch_values)

Issueによると、Ruby 2.3.0という比較的最近の時期にHash#fetch_valuesが実装された(#10017)ので、それに合わせてActiveRecordのHashWithIndifferentAccessクラスでも使えるようにしたそうです。

このクラスは以下のようにハッシュのキーに文字列でもシンボルでも与えられるようにするものです。indifferentは人間に対して使うと「無関心」「無頓着」というニュアンスですが、ここでは「寛容」のニュアンスですね。

rgb['white'] = '#FFFFFF'
rgb[:white]  # => '#FFFFFF'
rgb['white'] # => '#FFFFFF'

Rails: 有効なコネクションを初期化後にクリアするよう修正(Rails公式ニュースより)

# activerecord/lib/active_record/railtie.rb
+    initializer "active_record.clear_active_connections" do
+      config.after_initialize do
+        ActiveSupport.on_load(:active_record) do
+          clear_active_connections!
+        end
+      end
+    end

スレッドが変わってもコネクションを使いまわせるようにするためだそうです。

Rails: JSレスポンスパーサーのバグを修正(Rails公式ニュースより)

今度はCoffeeScriptのAjax周りです。document.bodyではなくdocument.headに追加するように修正されています。

# actionview/app/assets/javascripts/rails-ujs/utils/ajax.coffee
   if typeof response is 'string' and typeof type is 'string'
      if type.match(/\bjson\b/)
        try response = JSON.parse(response)
-    else if type.match(/\bjavascript\b/)
+    else if type.match(/\b(?:java|ecma)script\b/)
        script = document.createElement('script')
-      script.innerHTML = response
-      document.body.appendChild(script)
+      script.text = response
+      document.head.appendChild(script).parentNode.removeChild(script)
      else if type.match(/\b(xml|html|svg)\b/)
        parser = new DOMParser()
        type = type.replace(/;.+/, '') # remove something like ';charset=utf-8'

Rails: dependent: :destroyを指定した場合のbefore_destroyの挙動についてドキュメントを修正(Rails公式ニュースより)

以下が追加されました。Railsガイド「Active Record コールバック」の3-3. オブジェクトのdestroyに該当します。

注: before_destroyコールバックは、dependent: :destroyにともなってレコードが削除される前に実行されなければならないので、dependent: :destroy関連付けより前に実行するか、prepend: trueオプションを指定すること。

参考: Rails API Active Record Callbacks

Rails: input文字列のfreezeを修正(Rails公式ニュースより)


https://github.com/rails/rails/pull/28729/filesより

コメントから:

  • 「条件節やfreezeのtrue/falseまでdupしないといけないのはちとイケてない」
  • 「同意、でもブランチでの変更量は割りと少なくてすみそう」

k0kubunさんがRubyコミッターに

前からコミッターだったような気がしていましたが、今回からだったんですね。おめでとうございます!

Google Summer of Code 2017に参加する学生が決定(Rails公式ニュースより)

以下の2名に決まったそうです。おめでとうございます。

Marko Bogdanović
Assain

Sinatra 2.0がリリース(RubyWeeklyより)

Changelogがどこにあるかややわかりにくいのですが、https://github.com/sinatra/sinatra/blob/v2.0.0/CHANGELOG.mdにありました。

普段Sinatraを追っていませんが、Changelogの最後にIndifferentHashというものを見つけました。
上でも取り上げたActiveSupport::HashWithIndifferentAccessがちょうどBPSの社内勉強会でも一瞬話題になったので気になりました。

SinatraではSinatra::IndifferentHashなんですね。APIドキュメントの冒頭が泣かせます。

  # A poor man's ActiveSupport::HashWithIndifferentAccess, with all the Rails-y
  # stuff removed.

つっつきボイス「ActiveSupportでかいからね」「Sinatra的には使ったら負け、なのかな?」「SinatraはRailsのマウンタブルエンジンにもできるよ」

RailsPanel: Rails開発を支援するChrome拡張機能(RubyWeeklyより)


https://github.com/dejan/rails_panelより

RailsPanelは以前から人気の高いツールです。SQL文を見やすく整形してくれるあたりがうれしいですね。私も以前インストールしたことがある気がするのですが、クリーンインストールのときに消してしまったようです。

Railsアプリにmeta_request gemを追加してChromeウェブストアからインストールするだけで使えるようになります。

group :development do
  gem 'meta_request'
end

ActiveAdminが1.0でRails 5.1に対応(RubyWeeklyより)


https://activeadmin.info/より

つっつきボイス「管理画面系gemはカスタマイズしようとすればするほどハマる傾向があるなー」「カスタマイズなしで使える案件ってたぶんないでしょw」

Rackが404で返すヘッダにX-Runtimeがあるのヤバくね?(RubyWeeklyより)

HTTP/1.1 404 Not Found
Cache-Control: private, no-cache
Content-Type: text/html;charset=utf-8
Date: Mon, 29 Aug 2016 16:49:52 GMT
Request-Id: b3ca4a2c-1adf-4244-4cb0-17fbbc9deb06
Server: nginx/1.8.1
Strict-Transport-Security: max-age=31536000; includeSubDomains
Vary: Accept-Encoding
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Runtime: 0.018023806                  <-コレ
X-Xss-Protection: 1; mode=block
Content-Length: 0
Connection: keep-alive

このヘッダを生成しているのが、Railsを縁の下から支えているRackです。

# https://github.com/rack/rack/blob/master/lib/rack/runtime.rb#L12 より
  class Runtime
    FORMAT_STRING = "%0.6f".freeze # :nodoc:
    HEADER_NAME = "X-Runtime".freeze # :nodoc:
...

ユーザーが存在する場合としない場合でX-Runtimeが1桁近く違うので、これを使ってタイミング攻撃(この場合は辞書を食わせるなどしてユーザー名を特定)ができるのではないかという主張です。

# ユーザーが存在する場合
X-Runtime: 0.093990008
X-Runtime: 0.088857339
X-Runtime: 0.09251876
X-Runtime: 0.089843447
X-Runtime: 0.091845765
X-Runtime: 0.101260549

# ユーザーが存在しない場合
X-Runtime: 0.027787351
X-Runtime: 0.018023806
X-Runtime: 0.020997733
X-Runtime: 0.021645124
X-Runtime: 0.016645836
X-Runtime: 0.021828831
X-Runtime: 0.022211143

著者はこの問題をHerokuで見つけましたが、Heroku、BugCrowdともにあまり取り合ってもらっていない感じです。

つっつきボイス「影響の大きさ次第かな」「productionでX-Runtimeを表示しないぐらいはしてもいいかも」

引数にtrue/falseフラグを与えるのはコードが臭う前兆(RubyWeeklyより)

記事はそのまんまですが、そこからRubyMineの最近の機能であるparameter name hinting↓の話題に発展しました。

つっつきボイス「この機能、嫌いじゃない」「見た目のインデントが崩れるのいやだからオフにしてる」「デフォルトではパラメータ名と引数名が一致していれば表示されない」「挿入時にカーソルが置きにくい」

参考: Parameter Names Hinting

チュートリアル: RailsアプリをElastic Beanstalkにデプロイする(RubyWeeklyより)

元記事:

よくある記事ですが一応。

Active Model SerializerでRails APIサーバーを作る(RubyFlowより)

rails new--apiしてからカバレッジまでをひととおりカバーしています。

つっつきボイス「これ結構役に立ちそう」「Active Model Serializerについてあまり書かれてないけどねw」

Ralyxa: Amazon Alexaにアクセスするフレームワーク

Sinatraベースだそうです。AlexaはAmazon Echoのバックエンドにも使われているクラウド音声認識サービスです。
日本語版がいつ使い物になるかですね。

Rubyでバイナリデータを扱う(RubyFlowより)

Rubyによるビット操作、エンコードの検出、ビッグエンディアン・リトルエンディアンなどを解説しています。

そこから、Rubyはバイナリデータのハンドリングがイケているという話題になりました。私はテキスト処理がほとんどだったのでこのあたりは知りませんでした。

morimorihogeさんが「RubyでShiftJISのファイルを扱う(1.9.3, 2.0系対応版)」という記事を書いたことを思い出しながら、もっと前にJavaでやったときには「素のJavaにunsignedがないのでビット操作が不自由だったなー」「それ用のライブラリを使えば違ったかもしれないけど」と当時を回想していました。

他の記事もよい感じです。

Railsのテンプレートレンダリングのしくみ(RubyFlowより)

Railsで必ずといっていいほどお世話になっているビューテンプレートですが、実装はかなり生い茂っていることでも有名です。このあたりの解説はあまり見ないのでありがたいです。

スライドを見ていて「これ、Crafting Rails 4 Applicationsと構成が似ている気がするw」とmorimorihogeさんが気づきました。私も一応読んだはずなのに元ネタに気づけませんでした。そういえばこの本、未だに日本語化されていませんね。

著者のStan Loは台湾の人ですが、もしやと思ったら先週のウォッチで紹介したGobyの人でした。スライドを最後まで見るとわかります。

先のk0kubunさんもそうですが、RubyとGoを両方やっている人って意外にいますね。Goのpppecoなどもk0kubunさん作です。

JRubyのバグを見つけた話(RubyFlowより)

なにしろJRubyなのでJavaコードがほとんどです。

インテルが不揮発性メインメモリアーキテクチャのデモを公開

今朝morimorihogeさんがこのニュースを社内のSlackに流して一気に盛り上がりました。そのときの記事は日本語でしたが、意地で英語記事のリンクを貼りました。どんなふうに使おうかと夢は広がる一方です。

同記事には、まさにそのときのためにあるとしか思えないPersistent Memory Programmingというサイトも紹介されています。


http://pmem.io/2014/08/27/crawl-walk-run.htmlより

そして意外にも、このニュースが現時点でHacker Newsにまったく上がっていません。珍しいですね。

今から数時間以内ぐらいにHacker Newsに英語でタレこめばトップ取れるかもしれません。チャレンジャーは誰だ。

番外: 言語には人間性が反映される(RubyFlowより)

主にJRuby方面でご活躍のAlex Coles氏が、Sheffield Ruby User Groupの4月のカンファレンスでRubyや言語一般について自由に話している、雑学的に楽しい内容です。40分近くありますが、字幕も文字起こしもあり、日本人には聞き取りやすい英語だと思います。

個人的に、左のほっぺたのところのタトゥーが何の絵なのかが気になってしまいました。描いてる途中?

Wikipedia-ja: シェフィールド


今週は以上です。

関連記事

今週の主なニュースソース

ソースの表記されていない項目は独自ルート(TwitterやRSSなど)です。

Rails公式ニュース

Ruby Weekly

OpenRuby

RubyFlow

160928_1638_XvIP4h

Ruby on RailsによるWEBシステム開発、Android/iPhoneアプリ開発、電子書籍配信のことならお任せください この記事を書いた人と働こう! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

hachi8833

Twitter: @hachi8833、GitHub: @hachi8833 コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。 これまでにRuby on Rails チュートリアル第2版の半分ほど、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れてそれぞれ一部を翻訳。 かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。 仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

週刊Railsウォッチ

インフラ

BigBinary記事より

ActiveSupport探訪シリーズ