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

週刊Railsウォッチ(20171026)factory_girlが突然factory_botに改名、Ruby Prize最終候補者決定、PhantomJS廃止、FireFoxのFireBug終了ほか

こんにちは、hachi8833です。だんだん季節というものがわからなくなってきました。

10月最後のRailsウォッチ、いってみましょう。

Ruby Prize 2017の最終候補者3名が決定

いよいよ来週に迫ったRuby World Conference 2017の1日目、11/1のプログラム最後で表彰式が行われます。@solnicさん、@kamipoさん、@k0kubunさん、おめでとうございます。

dry-rbシリーズやrom-rb(ROM: Ruby Object Mapper)シリーズは、これまでもRailsウォッチやTechRachoでときどき扱ってきましたが、どちらも@solnicさんの作だったんですね。


2017.rubyworld-conf.org/ja)より

RubyWorld Conference 2017基調講演のタイトルが決まる

Rails: 今週の改修(Rails公式ニュースより)

Phantom.jsからSelenium/Chromeヘッドレスドライバに移行

# actionview/Rakefile
-      system("npm run lint && phantomjs ../ci/phantomjs.js http://localhost:4567/")
+      system("npm run lint && bundle exec ruby ../ci/qunit-selenium-runner.rb http://localhost:4567/")

つっつきボイス: 「Chromeヘッドレスドライバの導入は先週のウォッチでも取り上げたんですが、Phantom.js廃止の一環ということだったんですね」「Phantom.js使う機会なかったナー」
「それにしてもどうして替えたんだろう?」「ググってみたらこんなのありますね↓」「今年の4月だったのか」

N+1クエリ回避のためwith_attached_*を追加

# activestorage/lib/active_storage/attached/macros.rb
      has_one :"#{name}_attachment", -> { where(name: name) }, class_name: "ActiveStorage::Attachment", as: :record
       has_one :"#{name}_blob", through: :"#{name}_attachment", class_name: "ActiveStorage::Blob", source: :blob

+      scope :"with_attached_#{name}", -> { includes("#{name}_attachment": :blob) }
+
       if dependent == :purge_later
         before_destroy { public_send(name).purge_later }
       end

ignored_columnsにシンボルでリストを渡すと正常に動かなかったのを修正

何か変だなと思ったら、Rails公式ニュースのリンクが間違っていました。

# 修正前
self.ignored_columns = [:page_view] # `[]`のように動作

# 修正後
self.ignored_columns = [:page_view] # `['page_view']`のように動作

Rails UJSのAjaxコールバックを修正

# actionview/app/assets/javascripts/rails-ujs/utils/ajax.coffee
-  # Call beforeSend hook
-  options.beforeSend?(xhr, options)
-  # Send the request
+
+  unless options.beforeSend?(xhr, options)
+    return false
+
   if xhr.readyState is XMLHttpRequest.OPENED
     xhr.send(options.data)
-  else
-    fire(document, 'ajaxStop') # to be compatible with jQuery.ajax

 prepareOptions = (options) ->
   options.url = options.url or location.href

つっつきボイス: 「UJSあたりの動きってややこしくって: jQuery依存廃止のためにjquery-ujsがrails-ujsに替わって、さっきチェックしたら今年6月にRails 5.1で本体のAction Viewに組み込まれたんだそうです」

なおjquery-ujsのリポジトリは今もRailsの隣に残っていました。

Rails

FactoryGirlがfactory_botに名称変更(Awesome Rubyより)

factory_girl_railsもfactory_bot_railsに改名しました。

The name "Factory Girl" was confusing to some developers who encountered this library, and offensive or problematic to others. In October 2017 we renamed the library to "Factory Bot".
NAME.mdより

どの辺がoffensiveかまでは説明されていません。
今後factory_girlとfactory_girl_railsはどちらも非推奨になってwarningが表示されますが、factory_botと機能的に違いはないようです。


つっつきボイス: 「機能違ってたら困るわなー」「girlという言葉がいわゆるポリティカル・コレクトネスの問題に引っかかったんでしょうかね」「Factory Girlって映画があったらしいけどそれと紛らわしいってことなのかな?」「gemの方はRolling StonesのFactory Girlって曲↓が元らしいって聞いたような」「Stonesにそんな曲あったってシラナカッター」
「うろ覚えですけど、factory_girlのissueで「この名前でStonesと映画のどっちを連想する?」みたいな質問があがってて速攻閉じられてたのを見た気がします」

https://www.youtube.com/watch?v=9UZmtqpc6wM

曲は一発で好きになりました。

her: ORマッパーにRESTfulアクセスできるgem


github.com/remiprev/herより

Rails 5もサポートされています。

// remiprev/herより
// The response of GET /users/1
{ "id" : 1, "name" : "Tobias Fünke" }

// The response of GET /users
[{ "id" : 1, "name" : "Tobias Fünke" }]

morimorihogeさんが使ってみてよさそうと言ってたので」「ほほう、RESTfulなroutingでJSONを取れるとな」

AR関連付けのpreload/eager-loadingをテストする2つの方法(Awesome Rubyより)


blog.arkency.comより

# 同記事より
require 'test_helper'

class OrderTest < ActiveSupport::TestCase
  test "#last_ten eager loading" do
    o = Order.new()
    o.order_lines.build
    o.order_lines.build
    o.save!

    orders = Order.last_ten
    assert orders[0].association(:order_lines).loaded?
  end
end

つっつきボイス: 「preloadされてるか、eager-loadingされてるかのテストか: よさげ」「これ翻訳してみますね」

secureheaders: Twitter公式のセキュアヘッダー自動追加gem(Awesome Rubyより)

以下のようなHTTPヘッダーを自動で追加してくれます。Rails 4/5の他にsinatraもサポートしているようです。★2300超え。

  • Content Security Policy (CSP)
  • HTTP Strict Transport Security (HSTS)
  • X-Frame-Options (XFO)
  • X-XSS-Protection
  • X-Content-Type-Options
  • X-Download-Options
  • X-Permitted-Cross-Domain-Policies
  • Referrer-Policy
  • Public Key Pinning
  • Expect-CT
  • Clear-Site-Data

以前のウォッチでhttps://securityheaders.io/というチェックサービスを紹介しましたが、それとは別物のようです。


つっつきボイス: 「これ自分でやるのは大変なヤツだ」「デフォルト設定を与えるのが必須みたいですね」

アプリケーションサービスのよくある10の質問に答える(RubyFlowより)


blog.arkency.comより

  • アプリケーションサービスは複数のオブジェクトを読み取っていいの?: いいと思う
  • アプリケーションサービスは複数のオブジェクトを更新していいの?: 結合が強くなるのでおすすめしない
  • アプリケーションサービスが受け取る引数は何にすべき?: コマンドがいいと思う
  • など

つっつきボイス: 「DDD(ドメイン駆動設計)とあるので設計の話か」「割りといいこと書いてるかも: ときどきちょっとドキッとした」「それにしてもドメインという言葉って意味広すぎ」

Screencast: Capybaraでfeature test(RubyFlowより)


www.driftingruby.comより

15分の動画+コードサンプルです。


つっつきボイス: 「driftingruby.comってスクリーンキャストサイト知らなかったけど、エピソードリスト見るとそこそこ頑張ってる感じ」「ちゃんとコード例もページに載ってますね」「でないとみんな帰っちゃうから」

GraphQLとRelayとRailsで認証する(RubyFlowより)

# 同記事より
class GraphqlController < ApplicationController

  def execute 
    query = params[:query]
    context = {
      warden: warden,
      viewer: viewer
    }
    result = RailsRelayAuthenticationSchema.execute(query, variables: variables, context: context)

    render json: result
  end

  private

  def viewer
    warden.user || API::Viewer.new
  end

  def warden
    request.env['warden']
  end
end

つっつきボイス: 「Deviseの代わりにRack middlewareのWardenを直接使ってるのか」「Deviseだとプロジェクトには大きすぎることが多いから、だそうです」「これも翻訳しようかな」

[Rails] Devise Wiki日本語もくじ1「ワークフローのカスタマイズ」(概要・用途付き)

Rails Testing Grader: うちのテストが業界で遅い方かチェック(Ruby Weeklyより)


rails.testinggrader.comより


つっつきボイス: 「CIビルドの所要時間とコードとテストの行数を入れると算出してくれるのか: 雑に入れてみたらこんな感じになった↓」「一人でプログラミングしている人とかにはそれなりの指標になりそう」


rails.testinggrader.comより

RailsのログをJupyter Notebookでビジュアル表示(Ruby Weeklyより)


blog.scoutapp.comより


つっつきボイス: 「主に機械学習方面で使われているJupyter Notebookを使ってRailsのログをビジュアル化するというやつですね」「非開発者に渡して実行してもらうみたいな使い方できるかも」「JupyterはもともとPython用だったんですが、Ruby(iruby)とかいろんな言語でできるようになってて、実は結構好き: 勉強会に使ったりしてもよさそう」


jupyter.orgより

なおirubyはSciRubyの一部です。


sciruby.comより

action-cable-testing: ActionCableテスト支援ユーティリティ(RubyFlowより)

ActionCableのテストを書くときに使えそうです。

# palkan/action-cable-testingより
# spec/channels/chat_channel_spec.rb

require "rails_helper"

RSpec.describe ChatChannel, type: :channel do
  before do
    # initialize connection with identifiers
    stub_connection user_id: user.id
  end

  it "rejects when no room id" do
    subscribe
    expect(subscription).to be_rejected
  end

  it "subscribes to a stream when room id is provided" do
    subscribe(room_id: 42)

    expect(subscription).to be_confirmed
    expect(streams).to include("chat_42")
  end
end

つっつきボイス: 「全然関係ないけど、RailsのActiveResourceってさっぱり見かけないナ」「そういえば」

プログラマーのための命名ガイド(Awesome Rubyより)


blog.elpassion.comより

抽象化のレベルや「単一責任の原則」を意識するなどの命名ノウハウ記事です。


つっつきボイス: 「英語圏の人が英語圏に向けて書いている記事ではありますが」「命名、いつも難しいっす」「コードは勢いに乗って書けても、命名は勢いでやるわけにいかないところがつらいところでしょうね」
「ベテラン開発者は命名の達人でもあるんでしょうか?」「命名というより、ピタリと合う概念に到達する方を気にしてるなー」

Stop ActiveSupport Anywhere: ActiveSupportを他のgemとかに置き換えたい人向け情報


つっつきボイス: 「リストはまだ半分ぐらいしか埋まってませんが」「ActiveSupportを使わずに何とかしたい人っていうと、やっぱりSinatra?」「日付時刻系をActiveSupportなしでやるのは大変そう: このリストにも日付時刻系は載ってませんね」


sinatrarb.comより

Railsのトランザクションの書き方に気をつけよう(RubyFlowより)


ksylvest.comより

# 同記事より
survey = Survey.create(name: "Numbers")
question = Question.create(text: "What is Planck's constant?")

Survey.transaction do
  survey.update({ name: "", question_ids: [question.id] })
end
-- 同記事より
BEGIN
SELECT "questions".* FROM "questions" WHERE "questions"."id" = ...
SELECT "questions".* FROM "questions" INNER JOIN "questions_surveys" ON "questions"."id" = "questions_surveys"."question_id" WHERE "questions_surveys"."survey_id" = ...
INSERT INTO "questions_surveys" ("survey_id", "question_id") VALUES (..., ...)
COMMIT

つい先ほど公開された記事です。トランザクションの書き方に注意しないとアトミックでなくなってしまうことがあるという内容です。

RDBMS

PostgreSQLのドメイン統合機能(Postgres Weeklyより)


begriffs.comより

PostgreSQL系記事の豊富なブログです。

-- 同記事より
CREATE DOMAIN wgs84 AS geometry CHECK (
  -- a 2-dimensional point in our coord system
  st_ndims(VALUE) = 2 AND
  geometrytype(VALUE) = 'POINT'::text AND
  st_srid(VALUE) = 4326
);

ドメインを使用すると、共通な制約を1箇所にまとめることができ、メンテナンスに便利です。 たとえば、E-mailアドレスを格納する列が複数のテーブルで使用されていて、アドレス構文の検証のためすべてが同一のCHECK制約を必要としているような場合です。 このような場合、各テーブルに個別に制約を設定するよりも、ドメインを定義してください。
PostgreSQL 9.2.4文書: CREATE DOMAINより


つっつきボイス: 「ポスグレのドメインってデータ型なのか」「やっぱりドメインって言葉意味広すぎ」
「今ググって見つけた記事↓がわかりやすかった」「お、ナベアツw」「なつい」

-- 上記事より
CREATE DOMAIN nabeatsu AS INTEGER
CHECK (
  NOT (VALUE % 3 = 0 OR
  substring(VALUE::text from '3') is not null)
);

Ruby trunkより

提案: Procのブロックパラメータ割り当てをlazyに

ブロックパラメータ渡しが遅いのでlazyにしようというko1さんからの提案です。

# 遅い例
def block_yield
  yield
end

def block_pass &b
  # do something
  block_yield(&b)
end
  • メソッド冒頭ではブロックパラメータはnil
  • ブロックパラメータへのアクセスがあったらはじめてブロックからProcオブジェクトを作成
  • block_yield(&b)などでプロックパラメータを他に渡すときはProcオブジェクトを作成せず、ブロックの情報を渡す

つっつきボイス: 「lazyにすると速くなる理由、これだけ見てもよくわからんなー」「関係あるかどうかわかりませんが、JRubyだとブロックパラメータの方が速いみたいですヨ↓」

「おお、RailsにJRuby用のコードが↓」「これはRailsには入れたくないコードでしょうね」

# https://github.com/rails/rails/blob/v5.1.4/activerecord/lib/active_record/attribute_methods/read.rb#L63-L73 より
      # This method exists to avoid the expensive primary_key check internally, without
      # breaking compatibility with the read_attribute API
      if defined?(JRUBY_VERSION)
        # This form is significantly faster on JRuby, and this is one of our biggest hotspots.
        # https://github.com/jruby/jruby/pull/2562
        def _read_attribute(attr_name, &block) # :nodoc
          @attributes.fetch_value(attr_name.to_s, &block)
        end
      else
        def _read_attribute(attr_name) # :nodoc:
          @attributes.fetch_value(attr_name.to_s) { |n| yield n if block_given? }
        end
      end

Ruby

あれもこれもマジックと呼ぶのはやめて欲しい(RubyFlowより)


zverok.github.ioより

  • 若手が理解できないのはマジックではない
  • モンキーパッチはマジックではない
  • メタプログラミングだからマジックではない

つっつきボイス: 「何の話だろうと思ったら、おとといTechrachoでも翻訳を公開したRailsコードを改善する7つの素敵なGemにあった『マジックがあまり好きでない方はこのライブラリを使わなくてもよいでしょう』という一言に反論しているのか」

Railsコードを改善する7つの素敵なGem(翻訳)

Rubyメソッドを最短でプロファイリングする(Ruby Weeklyより)


samsaffron.comより

# 同記事より
# called once to patch in instrumentation
MethodProfiler.patch(SomeClass, [:method1, :method2], :name)

SomeClass.new.method1
SomeClass.new.method2

# called when starting profiling
MethodProfiler.start
result = MethodProfiler.stop

{ 
   total_duration: 0.2,
   name: {duration: 0.111, calls: 12}
}

つっつきボイス: 「ベンチマークでプロファイリングしやすくするパッチを書いたということみたいですね」「gemになってたらいいのに」

mina: Rubyデプロイツールの新顔gem(Awesome Rubyより)


mina-deploy/minaより

★3600超えです。

# minaドキュメントより
# config/deploy.rb
set :domain, 'flipstack.com'
set :user, 'flipstack'
set :deploy_to, '/var/www/flipstack.com'
set :repository, 'https://github.com/flipstack/flipstack.git'

task :deploy do
  deploy do
    # Put things that prepare the empty release folder here.
    # Commands queued here will be run on a new release directory.
    invoke :'git:clone'
    invoke :'bundle:install'

    # These are instructions to start the app after it's been prepared.
    on :launch do
      command %{touch tmp/restart.txt}
    end

    # This optional block defines how a broken release should be cleaned up.
    on :clean do
      command %{log "failed deployment"}
    end
  end
end

つっつきボイス:Capistrano的なデプロイツールみたいです」「SSHの使い方がCapistranoと違うのか」

Ruby HTTPライブラリgem 2種: httparty vs rest-client(Awesome Rubyより)

# jnunemaker/httpartyより
# Use the class methods to get down to business quickly
response = HTTParty.get('http://api.stackexchange.com/2.2/questions?site=stackoverflow')

puts response.body, response.code, response.message, response.headers.inspect
# ドキュメントより
# Skips SSL certificate verification
class Client
  include HTTParty

  base_uri "https://example.com"
  pem File.read("#{File.expand_path('.')}/path/to/certs/cert.pem"), "123456"

  def self.fetch
    get("/resources", verify: false)
    # You can also use something like:
    # get("resources", verify_peer: false)
  end
end
# rest-client/rest-clientより
>> response = RestClient.get 'http://example.com/resource'
=> <RestClient::Response 200 "<!doctype h...">
>> response.code
=> 200
>> response.cookies
=> {"Foo"=>"BAR", "QUUX"=>"QUUUUX"}
>> response.headers
=> {:content_type=>"text/html; charset=utf-8", :cache_control=>"private" ... }
>> response.body
=> "<!doctype html>\n<html>\n<head>\n    <title>Example Domain</title>\n\n ..."

マイクロサービスとかクローラやりたい人向けのようです。

nanobox: どこでもオールインワン開発環境(Awesome Rubyより)


guides.nanobox.ioより

大急ぎでちょっとだけ動かしてみました。nanobox.ioにアカウントを作ってガイドにしたがって操作すると、出来合いのアプリ環境をローカルVM(VirtualBox)内に自動構築します。Railsであればnanobox run rails sするとhttp://rails.dev:3000/でアプリが開きました。VMにはDockerも使えるけどまだおすすめしないそうです。


つっつきボイス: 「アカウントがあれば使えるみたいなので、でかいVMイメージを投げ合わずにリモート開発者と環境を完全に揃えたいときに便利なのかなと思いました」「rails.devでアクセスするために設定ツールがローカルDNSにちょっぴりパッチ当てますが」

shoryuken: Amazon SQSスレッドベースのメッセージ処理gem(Awesome Rubyより)

以前から知られているgemですが一応。

  • Rails Active Job
  • Queue Load balancing
  • Concurrency per queue
  • Long Polling
  • Batch processing
  • Auto extend visibility timeout
  • Exponential backoff
  • Middleware support
  • Amazon SQS CLI. See shoryuken help sqs

つっつきボイス:以前参加したミートアップで『shoryukenのコミッタと戦う』みたいな話がちらっとあったのが気になってます: こわい人なのかな?」「issueがほとんど残ってないのは凄いかも」

Rubyでsocketプログラミング(RubyFlowより)

# 同記事より
require 'socket'

puts "Starting the Server..................."
server = TCPServer.open(3000) # Server would listen on port 3000
loop{                         # Servers run forever
   client_connection = server.accept # Establish client connect connection
   client_connection.puts(Time.now) # Send the time to the client
   client_connection.puts("Closing the connection with #{client_connection}")
   client_connection.close      # Disconnect from the client
}

つっつきボイス: 「昔ながらのsocketプログラミングをやりたい人に」

Octotrack: Rubyアプリの依存関係とセキュリティを自動管理する有料サービス(RubyFlowより)


octotrack.comより

1プロジェクトなら無料だそうです。


つっつきボイス:bundler_auditでも同じようなことできそうですね」「bundler-auditは自分で動かさないとアラート出ないですけどね」「CIで回せばいいかも」

[Rails 5] rails newで常に使いたい厳選・定番gemリスト(2017-2018年版)

Ruby生き物図鑑: exceptionたち(RubyFlowより)


exceptionalcreatures.comより


つっつきボイス:図鑑、まだ2匹しかいない」「うーん、日本人には微妙なキャラデザイン」「萌え絵よりそれっぽくていいんじゃないですかね」「NoMethodErrorが攻撃力34.5で最強とは」

KEEP RUBY WEIRD 2017: 大胆なタイトルのRubyカンファレンス(Awesome Rubyより)


keeprubyweird.comより

こういうカンファレンスがあることを初めて知りました。米国テキサス州オースチンで10/27に開催だそうです。って今日ですね。


つっつきボイス: 「すごい色遣いとフォント...読みづらいw」「2014年から毎年やっているそうですが、Matzが一度も参加していないのが珍しいです」
「今年参加のYehuda Katzさんって確かすごい人だったと思う」「Ember.js/Rails/jQuery/Rust、いろいろやってる...たしかに凄い」

JavaScript

React.js v16がリリース

render() {
  // No need to wrap list items in an extra element!
  return [
    // Don't forget the keys :)
    <li key="A">First item</li>,
    <li key="B">Second item</li>,
    <li key="C">Third item</li>,
  ];
}

動画: Vue.js SPAでSEOする(JavaScript Liveより)

CSS/HTML/フロントエンド

FirefoxのFireBug、終了(Frontend Focusより)

コメントでも多くの人が別れを惜しんでいます。


hacks.mozilla.orgより


つっつきボイス: 「さいなら~」

Android

Android Studio 3.0とAndroid 8.1 Developer Previewがリリース

BPSのアプリチームが盛り上がってました。

Go言語

書籍『Goならわかるシステムプログラミング』


つっつきボイス: 「目次ものすごく多い...システムプログラミング全制覇する気か...」

その他

Steve Wozniakがコンピュータ教育プラットフォームを無償公開


つっつきボイス: 「とりあえずアプリ登録してみたんですが、上みたいな適性テストをいくつか解いたら『Javaをやってはどうでしょう』と言われちゃいました」「ほほー、ところでこの問題はフィボナッチ数列ですな」「ほんとだ、開始値が違うだけだったのか(ワカラナカッタ)」

番外

世界初の分子ロボットがイギリスで開発

なお下の動画は分子ロボットではなく普通の体内のようです。


今週は以上です。

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

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

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

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

Rails公式ニュース

Ruby Weekly

Awesome Ruby

RubyFlow

160928_1638_XvIP4h

postgres_weekly_banner

Frontend Weekly


CONTACT

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