Tech Racho エンジニアの「?」を「!」に。
  • 開発

週刊Railsウォッチ(20171020)Rubyが来年で25周年、form objectでサニタイズ、コアなString解説本ほか

こんにちは、hachi8833です。WPA2プロトコルの脆弱性の次は、特定のセキュリティチップでRSA秘密鍵の脆弱性が見つかったそうです。

10月3回目のRailsウォッチ、いってみましょう。

来年2/24に品川でRuby 25周年記念イベント


http://25.ruby.or.jp/より

Matzを始めとする講演がいくつか行われるそうです(詳細は変更の可能性あり)。

Ruby25 周年記念イベント開催実行委員会
委員長 まつもとゆきひろ(一般財団法人 Rubyアソシエーション理事長)
副委員長 井上 浩(ネットワーク応用通信研究所 代表取締役)
委員
- 前田修吾(ネットワーク応用通信研究所 取締役)
- 高橋征義(一般社団法人 日本Rubyの会 代表理事/株式会社達人出版会 代表取締役)
- 笹田耕一(一般財団法人 Rubyアソシエーション 理事/クックパッド株式会社)
http://25.ruby.or.jp/images/sponsorship.pdfより

Rails: 今週の改修

公式の更新がなかったのでcommitから見繕いました。

headless chrome driverとchromedriver-helper gemを追加

# actionpack/test/abstract_unit.rb
+class DrivenBySeleniumWithHeadlessChrome < ActionDispatch::SystemTestCase
+  driven_by :selenium, using: :headless_chrome
+end
# railties/lib/rails/generators/rails/app/templates/Gemfile
  # Adds support for Capybara system testing and selenium driver
   gem 'capybara', '~> 2.15'
   gem 'selenium-webdriver'
+  # Easy installation and use of chromedriver to run system tests with Chrome
+  gem 'chromedriver-helper'
   <%- end -%>
 end

つっつきボイス: 「上はy-yagiさんでした」「capybaraたんガンバレー」

GROUP BYORDER BYLIMITを使った場合のCOUNT(DISTINCT ...)を修正

# activerecord/lib/active_record/relation/calculations.rb
         if operation == "count"
           column_name ||= select_for_count
           if column_name == :all
-            if distinct && !(has_limit_or_offset? && order_values.any?)
+            if distinct && (group_values.any? || !(has_limit_or_offset? && order_values.any?))
               column_name = primary_key
             end
           elsif column_name =~ /\s*DISTINCT[\s(]+/i

つっつきボイス:#30886の問題が修正されたのか↓」

#30886より
モデル.group(:id).order('1 DESC').limit(30).distinct.count

# 期待するSQL(モデルは`device`)
SELECT COUNT(DISTINCT "devices"."id") AS count_id, "devices"."id" AS devices_id FROM "devices" GROUP BY "devices"."id" ORDER BY 1 DESC LIMIT $1

# 実際のSQL: SELECT COUNT(DISTINCT *)の部分がおかしい
SELECT COUNT(DISTINCT *) AS count_all, "devices"."id" AS devices_id FROM "devices" GROUP BY "devices"."id" ORDER BY 1 DESC LIMIT $1

db/schema.rbでMySQLのauto_increment: trueチェックを追加

# activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb
           def prepare_column_options(column)
             spec = super
             spec[:unsigned] = "true" if column.unsigned?
+            spec[:auto_increment] = "true" if column.auto_increment?

to_s(:db)をアルファベット文字列のrangeにも対応

# activesupport/lib/active_support/core_ext/range/conversions.rb
module ActiveSupport::RangeWithFormat
   RANGE_FORMATS = {
-    db: Proc.new { |start, stop| "BETWEEN '#{start.to_s(:db)}' AND '#{stop.to_s(:db)}'" }
+    db: -> (start, stop) do
+      case start
+      when String then "BETWEEN '#{start}' AND '#{stop}'"
+      else
+        "BETWEEN '#{start.to_s(:db)}' AND '#{stop.to_s(:db)}'"
+      end
+    end
   }

つっつきボイス:Range#to_s(:db)ってのがあるとは」「手元のRails環境でrails consoleやってみると確かにString(アルファベット文字)でto_s(:db)がエラーになる↓: これが修正されたということか」

irb(main):003:0> range = (1..100)
=> 1..100
irb(main):004:0> range.to_s
=> "1..100"
irb(main):005:0> range.to_s(:range)
=> "1..100"
irb(main):006:0> range.to_s(:db)
=> "BETWEEN '1' AND '100'"
irb(main):007:0> range = ('a'..'z')
=> "a".."z"
irb(main):008:0> range.to_s(:db)
ArgumentError: wrong number of arguments (given 1, expected 0)
        from (irb):8

「他にも#to_s(db)できるクラスってあるかな: お、ActiveSupport::TimeWithZoneにもある」

    # Returns a string of the object's date and time.
    # Accepts an optional <tt>format</tt>:
    # * <tt>:default</tt> - default value, mimics Ruby Time#to_s format.
    # * <tt>:db</tt> - format outputs time in UTC :db time. See Time#to_formatted_s(:db).
    # * Any key in <tt>Time::DATE_FORMATS</tt> can be used. See active_support/core_ext/time/conversions.rb.
    def to_s(format = :default)
      if format == :db
        utc.to_s(format)
      elsif formatter = ::Time::DATE_FORMATS[format]
        formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
      else
        "#{time.strftime("%Y-%m-%d %H:%M:%S")} #{formatted_offset(false, 'UTC')}" # mimicking Ruby Time#to_s format
      end
    end

RailsのRuboCopを0.50.0にアップデート

# .codeclimate.yml
 engines:
   rubocop:
     enabled: true
-    channel: rubocop-0-49
+    channel: rubocop-0-50

つっつきボイス: 「今さらですが、Railsフレームワーク開発にもRuboCopが使われているんだなと思って」「CodeClimateで回してますな」


codeclimate.comより

Rails

RubyのアプリサーバーがMac OS High Sierraで落ちる理由


blog.phusion.nlより

この間のRailsウォッチでPumaが落ちる問題(#1421)をお伝えしましたが、他のRubyサーバーも含め、原理や対応策を詳しく解説しています。PassengerでおなじみのPhosionなので、Passengerは次の5.1.11でこの問題の回避策を含めるそうです。

High SierraでObjective-Cライブラリが変更されたことで顕在化しましたが、根本的にはマルチスレッドとfork()が絡み合った問題であり、Linuxも無縁ではないそうです。


つっつきボイス: 「High Sierraでは落ちるべきときに即落ちるようになったということか」「マカーだけどMacで本番サーバーを動かすことはないし、最近はDocker使うことも多いのでそっちに移行すればいいんじゃないかしら」

Puma/Unicorn/Passengerの効率を最大化する設定(Awesome Rubyより)


speedshop.coより

以前もTechRachoでパフォーマンス関連の記事を翻訳させていただいたNate Berkopecさんが以下の値の設定について解説しています。

  • 子プロセス数
  • スレッド数
  • Copy-on-write
  • コンテナサイズ

つっつきボイス: 「解説系の記事だけど、もう少しだけ指標をバシッとわかりやすく出してくれたらうれしいかな: Rails serverに特化しているようでもないし」「例のComplete Guide to Rails Performanceの著者なので、そっちを買ってくださいということかもですね」

railsspeed.comより

default_scopeを使ってはいけない理由(Ruby Weeklyより)


andycroll.comより

とても短い記事です。他の記事も小粒に抑えられていて読みやすいです。


つっつきボイス: 「うんうん、ActiveRecordのdefault_scopeは使うと後で困ったことになるやつ」「ちょうどBPSの新人君がこの間default_scope踏んで相当頭にきてた」

よくある?Rails失敗談 default_scope編

書籍: Effective Testing with RSpec 3(Ruby Weeklyより)


pragprog.comより


つっつきボイス: 「RSpec 3の基本を学ぶにはよさそうかな」「ただ、実際業務で欲しいテストケースやマッチャーを本だけで網羅するのはたぶん不可能: たとえばDBが4つあるアプリのテストをどうやって書くか、とか」「そこから先は自分で頑張るかググって調べることになりますね」

form objectで属性をサニタイズする(Awesome Rubyより)


drivy.engineeringより

短いですが良記事です。

# 同記事より
class SanitizedVatNumber < Virtus::Attribute
  def coerce(value)
    value.respond_to?(:to_s) ? value.to_s.gsub(/\s+/, '') : value
  end
end

つっつきボイス: 「おー、こういうの結構好き: form objectVertusは相性がいいし、そこに#coerceを組み合わせるのがうまい」「テストが単純になるのもいい」

参考

肥大化したActiveRecordモデルをリファクタリングする7つの方法(翻訳)

ActiveRecordクエリのトリック


medium.com/rubyinsideより

  1. 関連付けられたテーブルに条件付きでJOIN
  2. nested JOINする別の方法
  3. 存在確認クエリ
  4. サブクエリ
  5. ActiveRecordの基本を思い出そう
  6. 論理値

つっつきボイス: 「新しい話は特にないけど、クエリの使い方の一覧として見ておくといいかも」

Railsで動的なエラーページを作る(RubyFlowより)


pooreffort.comより


つっつきボイス: 「エラーページを動的にしたい気持ちはわかるけど、Railsサーバーが死んだら表示されなくなるのでおすすめしない」

Rails APIにはどのJSON Serializerがいいか(RubyFlowより)


www.carlosramireziii.comより


つっつきボイス: 「Jbuilderは最近それほど評価されてないのをよく見かけるので、ActiveModel::Serializersが市民権を獲得しつつあるのかもしれない」

Rails: ActiveModelSerializersでAPIを作る–Part 1(翻訳)

Aruba: コマンドラインツールをCucumber/RSpec/Minitestでテストするgem(Awesome Rubyより)

1か月ほどで★700個超えです。


つっつきボイス: 「どうやって使うのかなと思ったら、#run_commandなどのhelperを追加してCLIのテストを書けるようにしているのか↓」

# app.cucumber.proの /04_aruba_api/command/find_a_started_command.feature より
require 'spec_helper'

RSpec.describe 'Run command', :type => :aruba do
  before(:each) { run_command('echo hello') }
  let(:command) { find_command('echo hello') }

  before(:each) { stop_all_commands }

  it { expect(command).to be_successfully_executed }
  it { expect(command.commandline).to eq 'echo hello' }
end

ReportsKit: Railsで使える美しいチャート/表(Ruby Weeklyより)


github.com/tombenner/reports_kitより


つっつきボイス: 「この種のChartライブラリは他にもあるけど、JSのobjectでとても深いnested設定オブジェクトを作る代わりにYAMLで設定書ける↓というのはそれだけで嬉しいですね」「サイトでBootstrap使っているのがひと目でわかる」

measure: post
filters:
- author
- created_at
dimensions:
- created_at
- author
chart:
  type: line
  options:
    scales:
      yAxes:
      - stacked: true

Redisの作者だけど15年間英語で苦しみまくってた

英語の学習速度がこんなに遅かったのは、習い始めに英語を目で読んでばかりでリスニングをやってなかったせいだ。おかげで発音がめちゃめちゃなまま単語を覚えてしまった。今英語学んでるやつに言っとく: 話せるようになりたかったら絶対リスニングやれ。

4年前の記事ですが、ほろっときたので翻訳しようと思います。


redis.ioより

Railsのディレクトリを解説(Ruby Weeklyより)

一度見れば十分だと思いますが、Rails本体だけでなく、著名なgemで追加されるディレクトリも解説しているのが珍しいと思いました。

nullalign: NOT NULL制約のつけ忘れを警告するgem(Ruby Weeklyより)

$ bundle exec nullalign
There are presence validators that aren’t backed by non-null constraints.
--------------------------------------------------------------------------------
Model              Table Columns
--------------------------------------------------------------------------------
Album              albums: name, owner_id
AttendanceRecord   attendance_records: group_id, attended_at
CheckinLabel       checkin_labels: name, xml
CheckinTime        checkin_times: campus
CustomField        custom_fields: name, tab_id

作者のTom CopelandさんはRuby Hero 2008の受賞者です。

PgParty: Active RecordのPostgreSQL 10パーティショニングgem(Ruby Weeklyより)

# github.com/rkrage/pg_partyより
class CreateSomeListRecord < ActiveRecord::Migration[5.1]
  def up
    create_list_partition :some_list_records, partition_key: :id do |t|
      t.text :some_value
      t.timestamps
    end

    create_list_partition_of \
      :some_list_records,
      partition_key: :id,
      values: (1..100).to_a

     create_list_partition_of \
       :some_list_records,
       partition_key: :id,
       values: (100..200).to_a
  end
end

つっつきボイス: 「PostgreSQL 10のRange Partitioningはとても簡単に使えるようになってていいらしい」「↓この記事がわかりやすかった」

Vanilla Rails: Railsのgemをどこまで断捨離できるか(Awesome Rubyより)

メリットは「速い」「わかりやすい」「gemにわずらわされない」など、デメリットは「生産性が落ちた」「車輪の再発明」だったそうです。


つっつきボイス: 「rspec-railsとhttpとactive_model_serializersだけは手放せないのね」
httpってgemあるんですね↓: すごく検索しにくそう」「Net::HTTPとは別のHTTPクライアントですが、今ならhttp_clientかな」

Rails 5ブロンズ試験のベータ版が11/12に実施

Ruby trunkより

ubygems.rbを削除(Ruby Weeklyより)

# tool/sync_default_gems.rb
   case gem
    when "rubygems"
 -    `rm -rf lib/rubygems* lib/ubygems.rb test/rubygems`
 +    `rm -rf lib/rubygems* test/rubygems`
      `cp -r ../../rubygems/rubygems/lib/rubygems* ./lib`
 -    `cp -r ../../rubygems/rubygems/lib/ubygems.rb ./lib`
      `cp -r ../../rubygems/rubygems/test/rubygems ./test`

ubygems.rbって何だろうと思ったら、オプションを-rubygemsと書けるようにするためだけのものでした」「あー、あるあるそういうの」「このオプションに別れを惜しむ人が結構いるんですね↓」


e5e1f9より

Ruby

Rubyのreduceの基本を知る

# 同記事より
def select(list, &fn)
  list.reduce([]) { |a, i| fn[i] ? a.push(i) : a }
end
select([1,2,3]) { |i| i > 1 }
# => [2, 3]

つっつきボイス:#inject#reduce(同じだけど)は使うたびにちょっとドキドキする」「#injectって実はパフォーマンスあまりよくなくて、最近は#sumの方が速かったりしますけどね」「reduceの動作をLispで説明しているのがわかりやすいかも↓」

(+ (+ (+ (0) 1) 2) 3)

rotoscope: 高速メソッド呼び出しロガーgem(Ruby Weeklyより)

まだ★は少ないですが、Shopifyなので一応。ちょっとしたデバッグに便利そうです。

# github.com/Shopify/rotoscopeより
require 'rotoscope'

class Dog
  def bark
    Noisemaker.speak('woof!')
  end
end

class Noisemaker
  def self.speak(str)
    puts(str)
  end
end

log_file = File.expand_path('dog_trace.log')
puts "Writing to #{log_file}..."

Rotoscope.trace(log_file) do
  dog1 = Dog.new
  dog1.bark
end

こんなふうにログを取れます。

event,entity,method_name,method_level,filepath,lineno
call,"Dog","new",class,"example/dog.rb",19
call,"Dog","initialize",instance,"example/dog.rb",19
return,"Dog","initialize",instance,"example/dog.rb",19
return,"Dog","new",class,"example/dog.rb",19
call,"Dog","bark",instance,"example/dog.rb",4
call,"Noisemaker","speak",class,"example/dog.rb",10
call,"Noisemaker","puts",class,"example/dog.rb",11
call,"IO","puts",instance,"example/dog.rb",11
call,"IO","write",instance,"example/dog.rb",11
return,"IO","write",instance,"example/dog.rb",11
call,"IO","write",instance,"example/dog.rb",11
return,"IO","write",instance,"example/dog.rb",11
return,"IO","puts",instance,"example/dog.rb",11
return,"Noisemaker","puts",class,"example/dog.rb",11
return,"Noisemaker","speak",class,"example/dog.rb",12
return,"Dog","bark",instance,"example/dog.rb",6

つっつきボイス: 「rotoscope、何かの発表で使っているところを見たような気がする」

GCPのStackdriverでRubyアプリのデバッグとログ出力が可能に


つっつきボイス: 「ここRailsでも使えるかな?」「使えるみたいです↓」「おー、StackDriverでRailsのログ見られるのいいな: Dockerコンテナでログをどうやって収集するかがいつもつらみなんで」

GitHubリポジトリ: stackdriver

Haml 5.0.4がリリース

Rubyで関数型プログラミング(Ruby Weeklyより)

同記事で以下のPFaaOという見慣れないパターンに言及していました。


つっつきボイス: 「pure functionは関数型言語で言う関数のようだ: 入力が同じなら必ず出力が同じ」
「数学だとそういうの何って言いましたっけ...」「単射かな」「単射は英語でinjective mappingなのかー」

k0kubunさんの「YARV-MJIT」記事

RubyKaigi 2017のLTではLLVMでJITをやっていたのが、今度はYARVでやってみたそうです。


つっつきボイス: 「k0kubunさんまじつよい」

mrubyのdo end内でrescueできるようになった

↓このコミットのようです。

書籍: Mastering Ruby Strings and Encodings(Ruby Weeklyより)

この間のTechRacho翻訳記事「ガイジン向けRubyKaigiガイド」の著者であるRichard Schneeman氏の推薦文付きです。

# 同記事より
'é' == 'é' # => false
[128077, 32, 128078].pack('U*')

つっつきボイス: 「これ個人的に好きな内容: 買ってみよう」「Stringだけで1冊書くってすごい」
「普通なら表示できない文字もpackでできると」「packって確かC言語由来でしたっけ」

Rubyカンファレンスを初めて仕切ってみた感想(Ruby Weeklyより)


2017.southeastruby.comより

以前のウォッチでも紹介したSouthEast Ruby 2017です。


つっつきボイス: 「カンファレンスの運営はほんと大変だと思う」「ざっくりだけど、会場費8000ドルといった予算も記事に書かれているのがいいですね: 自分でやってみたい人には参考になるかも」

台湾で2018年4月にRubyとElixirのカンファレンスが開催


2018.rubyconf.twより


つっつきボイス: 「RubyとElixirが並ぶカンファレンス初めて」「Rubyが液化して滴ってるみたいダナー」

JavaScript

JavaScriptの正規表現の奥深い概念


geekstrick.comより

// 同記事より
  var myRegExp = /Geeks Trick/igm;
  alert("Source: " + myRegExp.source + 
        "\n Ignore Case : " + myRegExp.ignoreCase +  
        "\n Global : " + myRegExp.global + 
        "\n Multiline : " + myRegExp.multiline +
        "\n Last Index: " + myRegExp.lastIndex)

つっつきボイス: 「JSの正規表現、もうちょっと知っておきたいので読んでみようかな」「JSの正規表現はlook behindがないのが常々残念です: パフォーマンス悪いのはわかってるんですが」「\p{Katakana}みたいなUnicode文字クラス指定もないし」

CSS/HTML/フロントエンド

Mozillaの新生MDN Web DocsにMicrosoft/Google/W3C/Samsungなども参加


blogs.windows.comより

複数ブラウザ向けのWeb関連ドキュメントがWeb Docsに集約されることになるようです。Appleはリストに載ってませんね。

その他

DockerがKubernetesをネイティブサポート


blog.codeship.comより


つっつきボイス: 「これはもしかするとDocker Swarmの終了が近いのかな? Docker Swarmをproductionで使っているのを見たことないけど」

developerブートキャンプは衰退期に入ったか

ここには引用しませんが、記事からリンクされているReuterの統計情報を見ると2014年をピークに激減しています。

Algorithmia: AI機能のマーケットプレイス


algorithmia.comより

Googleが出資しているそうです。とりあえずアカウントを作って検索してみたところ、「japanese」ではまだ6件でしたが、その場で試すこともできました。


lgorithmia.comより

Alpha Goがゼロから学習して既存の人工知能を破る


deepmind.comより

番外

ネイティブみたいに発音できなくてもいい

この@e_kazumaさんの「今日のタメ口英語」は言葉のセンスが今風かつ非常によくて気に入りました。


今週は以上です。

バックナンバー(2017年度)

週刊Railsウォッチ(20171013)Ruby 2.5.0-preview1リリース、RubyGems 2.6.14でセキュリティバグ修正、Bootstrap 4.0がついにBetaほか

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

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

Ruby 公式ニュース

Rails公式ニュース

Ruby Weekly

Awesome Ruby

RubyFlow

160928_1638_XvIP4h

Frontend Weekly

frontendweekly_banner_captured

Hacker News

160928_1654_q6srdR


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。