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

週刊Railsウォッチ(20171222)定番gemまとめサイト、active_record-mtiでテーブル継承、PostgreSQL 10の非互換変更点、Railsガイド攻略法ほか

こんにちは、hachi8833です。Ruby 2.5リリースまでもう少しです。

Rails勉強会@東京 第93回に初参加させていただきました。2年半ぶりの開催だったそうです。

お知らせ: 年末年始にかけて週刊Railsウォッチをお休みいたします: 次回は1月12日です。

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

Rails: 今週の改修

今週の更新情報は多めなので選別してみました。

セキュリティ関連ヘッダーを追加

# actionpack/lib/action_dispatch/railtie.rb#26
     config.action_dispatch.default_headers = {
       "X-Frame-Options" => "SAMEORIGIN",
       "X-XSS-Protection" => "1; mode=block",
-      "X-Content-Type-Options" => "nosniff"
+      "X-Content-Type-Options" => "nosniff",
+      "X-Download-Options" => "noopen",
+      "X-Permitted-Cross-Domain-Policies" => "none"
     }

つっつきボイス: 「X-で始まるヘッダって確かIE向けがほとんどだったと思うはRFC定義されていない独自拡張を表している」「X-Download-Options(IE向け)はまだわかるけど、↓の良記事見るとFlashがらみのヘッダが目につくなー: Railsでそこまで手を回すのってどうなんだろ?」「secureheadersにもこのヘッダ入ってるんで、セキュリティ関係者が入れときたいと思ってるらしいことはワカッタ」「10月のウォッチで扱ったgemですね」

db.createのエッジケースを修正

スキーマキャッシュの読み込み時には現在のマイグレーションバージョンをフェッチする。
しかしデータベースが存在しない場合に接続を取れずにエラーになる。これはデータベース作成時に問題になる。
データベースがない場合はスキーマキャッシュは不要なのでエラーを無視するよう修正。
#31311より大意

# activerecord/lib/active_record/migration.rb#56
-      def current_version(connection = Base.connection)
+      def current_version(connection = nil)
+        if connection.nil?
+          begin
+            connection = Base.connection
+          rescue ActiveRecord::NoDatabaseError
+            return nil
+          end
+        end

ActiveStorage::Blobからvariantを削除

# activestorage/app/models/active_storage/blob.rb#273
  def delete
-    service.delete key
+    service.delete(key)
+    service.delete_prefixed("variants/#{key}/") if image?
 @kaspth

つっつきボイス: 「variantって、作成した後削除し忘れてつまづきがちなやつ」「ところでblobって言葉ここに限らずいろんなところで見かけるんですが、どんな意味でしたっけ」「だいたいバイナリを表すことが多いっすね」「バイナリ・ラージ・オブジェクトの略なのか」「オブジェクト指向のオブジェクトではないw」

Railsのblobについての記述は以下にありました。

blobは、そのサービス上にあるファイルの位置を示すファイルとキーについてのメタデータを含むレコードです。
rails/activestorage/app/models/active_storage/blob.rbより大意

Railsの起動メッセージがきびきび表示されるようになった

起動直後に=> Booting Railsを表示するようになりました。

# railties/lib/rails/generators/rails/app/templates/config/boot.rb.tt#3
require 'bundler/setup' # Set up gems listed in the Gemfile.
require 'bootsnap/setup' # Speed up boot time by caching expensive operations.
+
+if %w[s server c console].any? { |a| ARGV.include?(a) }
+  puts "=> Booting Rails"
+end

つっつきボイス: 「これは地味にうれしい」「今までなかったのが不思議ですね」

foreign_keysinformation_schemaを修正

初コミットおめでとうございます。

# activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb#406
-          FROM information_schema.key_column_usage fk
-          JOIN information_schema.referential_constraints rc
+          FROM information_schema.referential_constraints rc
+          JOIN information_schema.key_column_usage fk
           USING (constraint_schema, constraint_name)
           WHERE fk.referenced_column_name IS NOT NULL
             AND fk.table_schema = #{scope[:schema]}
             AND fk.table_name = #{scope[:name]}
+            AND rc.constraint_schema = #{scope[:schema]}
             AND rc.table_name = #{scope[:name]}

つっつきボイス: 「これはMySQL向けだな: information_schemaがあるからすぐわかる」「JOINの方向を逆にしたのか」

SQLを発行したコードの行をオプションで出力

development.rbでconfig.active_record.verbose_query_logs = trueとすることでapp/views/news/show.html.erb:9:inのように出力されるようになりました。

# 26815より
Started GET "/news/popular" for ::1 at 2016-10-19 00:57:48 +0200
Processing by NewsController#popular as HTML
  Version Load (57.3ms)  SELECT  "versions".* FROM "versions" INNER JOIN "rubygems" ON "rubygems"."id" = "versions"."rubygem_id" LEFT OUTER JOIN "gem_downloads" ON "gem_downloads"."rubygem_id" = "rubygems"."id" AND "gem_downloads"."version_id" = $1 WHERE ("versions"."created_at" BETWEEN '2016-10-11 22:57:48.145796' AND '2016-10-18 22:57:48.145965') AND "versions"."indexed" = $2  ORDER BY gem_downloads.count DESC, "versions"."created_at" DESC LIMIT 10 OFFSET 0  [["version_id", 0], ["indexed", "t"]]
  ↳ app/views/news/show.html.erb:9:in `_app_views_news_show_html_erb___2784629296874387000_70222193538980'
  Rubygem Load (0.4ms)  SELECT  "rubygems".* FROM "rubygems" WHERE "rubygems"."id" = $1 LIMIT 1  [["id", 19969]]
  ↳ app/views/news/_version.html.erb:1:in `_app_views_news__version_html_erb__2744651331114605013_70222191156360'
  Version Load (0.8ms)  SELECT  "versions".* FROM "versions" WHERE "versions"."rubygem_id" = $1 AND "versions"."latest" = $2  ORDER BY "versions"."position" ASC LIMIT 1  [["rubygem_id", 19969], ["latest", "t"]]
  ↳ app/helpers/application_helper.rb:23:in `gem_info'
  GemDownload Load (0.3ms)  SELECT  "gem_downloads".* FROM "gem_downloads" WHERE "gem_downloads"."version_id" = $1 AND "gem_downloads"."rubygem_id" = $2 LIMIT 1  [["version_id", 882133], ["rubygem_id", 19969]]
  ↳ app/models/version.rb:247:in `downloads_count'

つっつきボイス: 「これはマジありがたい!: eager-loadingしまくってるとどうなるかというのはあるけれど」「そういえばこの間joker1007さんが『activerecord-cause gemは役割を終えた』みたいなことを言ってたのはこの修正のことかな?」「ちょうどこの間のウォッチでactiverecord-cause取り上げたところだった」

nobuさんの珍しいコミット

# 81b99b2 と 2d5700b
-    @cache_path = Tempfile.create(%w{tmp cache}, Dir.tmpdir)
+    @cache_path = Dir.mktmpdir(%w{tmp cache})

# bff3ee8 と 4022f33
-    @cache_path = File.join Dir.tmpdir, Dir::Tmpname.make_tmpname('tmp', 'cache')
+    @cache_path = Tempfile.create(%w{tmp cache}, Dir.tmpdir)

つっつきボイス: 「Rails勉強会@東京で話題になってたので」「nobuさんはRubyのコミッターだからRailsにコミットするのは確かに珍しいかも」「それ用のメソッドがRubyにあるから使おうよ、ってことですね」

なおRubyとRailsの両方で活発に活動している方はAaron Patterson氏を始め結構います。

[インタビュー] Aaron Patterson(前編): GitHubとRails、日本語学習、バーベキュー(翻訳)

Rails

active_record-mti: PGネイティブの継承テーブルをARで使うgem

Rails勉強会@東京で評判がよかったやつです。

# TwilightCoders/active_record-mtiより
ActiveRecord::Schema.define(version: 20160910024954) do

  create_table "accounts", force: :cascade do |t|
    t.jsonb    "settings"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "users", inherits: "accounts" do |t|
    t.string "firstname"
    t.string "lastname"
  end

  create_table "developers", inherits: "users" do |t|
    t.string "url"
    t.string "api_key"
  end

end

つっつきボイス: 「MTI: Multiple Table Inheritance」「PostgreSQLにテーブル継承できる機能があるのは知ってたし、6系の頃に使ったことあったけど多重継承できるのか↓: READMEのサンプルでは多重継承してないけど↑」「いやほんと、ぽすぐれのテーブル継承、普通に使えるし便利やで?」「STIだとカラム増えすぎるんですよね」

CREATE TABLE boatcar () INHERITS (boat,car);

「やっぱりぽすぐれいいな」「ビュー(データベースビュー)もいいし: Railsにcreate view、ほすぃ~」「同意」「同意」

ついでに9.6でこんな記述を見つけました。

親テーブル上の検査制約と非NULL制約はその子テーブルに自動的に継承されます。 他の種類の制約(一意性制約、プライマリキー、外部キー制約)は継承されません
PostgreSQL 9.6 - 5.8. 継承より

Rails: STI(Single Table Inheritance)でハマったところ

active_mocker: ARのモックを生成するgem

これもRails勉強会で話題でした。

# 同リポジトリより
require 'rspec'
require 'active_mocker/rspec_helper'
require 'spec/mocks/person_mock'
require 'spec/mocks/account_mock'

describe 'Example', active_mocker:true do

  before do
    Person.create # stubbed for PersonMock.create
  end

end

つっつきボイス: 「schema.rbが更新されるとモックがfailする、と」「ARでDBアクセスしないなら当然速くなるな」「ただDBMSに入れてloadし直すことによって挙動変わる場合はどうなるんだろう」「fasterなテストとして普段はactive_mocker: trueを回しておいて、定期実行では普通にDB使って回す方が、DBMSが型変換したりするケースとかも考えれば安全そう」

RubyWeeklyの「2017年人気記事リスト」(Ruby Weeklyより)

年の瀬を感じる企画ですね。TechRachoで翻訳した記事もいくつか見当たりました。


rubyweekly.comより


つっつきボイス: 「英語圏のネット系マガジンは軒並み1月までお休みですね: さすがクリスマス最優先な文化圏」「TechRachoでもこの企画やればいいのに」「来週やりましょう!」

get_schwifty: ActionCableでRailsビューの一部をバックグラウンドレンダリング(Ruby Weeklyより)

# 同リポジトリより
# app/cables/calculator_cable.rb
class CalculatorCable < BaseCable
  def fibonacci
    n = SecureRandom.rand(30..40)
    calculated = calculate_fibonacci(n)
    stream partial: "calculator/fibonacci", locals: { calculated: calculated, n: n }
  end

  private

  def calculate_fibonacci(n)
    return n if n <= 1
    calculate_fibonacci( n - 1 ) + calculate_fibonacci( n - 2 )
  end
end

つっつきボイス: 「これとよく似たgemがあったなー: render_asyncだ」「TechRachoで記事にしてました↓」

Rails: render_async gemでレンダリングを高速化(翻訳)

「render_asyncは素直にjQueryで遅延loadingしていてとてもわかりやすい: その代わりStreamとかはできない」
「そしてこちらのget_schwiftyはActionCable使ってStream APIで転送するので、render_asyncよりもさらにいい感じに出せる: ただしTCPセッション消費するからworker枯渇が怖いけど」

技術的負債調査のポイント10個


codeclimate.comより


つっつきボイス: 「こちらCode Climateブログの記事です」「お、Code Climateブログって記事本数は少ないけど質がとっても高いんで信頼できる: だいたいほぼ文句付けようのないレベル」「私も読んでて同じこと思ったので次で過去記事掘り起こしてみました」

古典技術記事探訪: CodeclimateやSemaphore.ciブログ

いずれも2014年の記事ですが、今も通用しそう。


つっつきボイス: 「1は例の定番記事『肥大化したActiveRecordモデルをリファクタリングする7つの方法』で一番多かった質問『どうしてクラスメソッドでできることをわざわざインスタンスメソッドにするの?』に答えたものだそうです」「前にも話したけど、クラスメソッドで作ったものを後でインスタンスメソッドに変えるのはほんとつらい」

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

「4の図↓もよかったので」「さっきのactive_mockerとかは、まさにこのピラミッドの左下を目指すためのもの」「単体テストほど軽く速くするということですね」


codeclimate.comより

Faktory: バックグラウンドジョブサーバー

ちょっと検索しにくい名前ですが。


contribsys/faktoryより

Q. productionで使えますか?
A. なにぶん新しいプロジェクトなので、リスクを許容できるのならば。APIが安定したら1.0をリリースする予定で、自分では安定していると思います。

Q. FaktoryにはRedis必要ですか?
A. 不要です。Faktoryはスタンドアロンの64ビットLinuxバイナリであり、ジョブを回すのにFaktoryワーカープロセスが必要です。「Redis -> Sidekiq」 == 「Faktory -> Faktory worker」という関係です。

Changelog: 技術系Podcast

上のPodcastもここです。Rails勉強会でこのPodcastをチェックしている人が結構いたので。


changelog.comより


つっつきボイス: 「みっちり文字起こししているところが凄いんですよ」「こういうのがありがたいっすね: 検索でも見つけやすいし」

Decoratorを比較


  • 素のdecorator
  • Module + Extend + Super decorator
  • Plain Old Ruby Object decorator
  • Class + Method Missing decorator
  • SimpleDelegator + Super + Getobj decorator

thoughtbotの記事です。2015年ですがまとまりがよかったので。


つっつきボイス: 「ちょっと前に見つけた別のDecorator記事が構成的にちょっと残念だったので」「うんうんそういうのよくあるw」

Railsガイドで怖気づいた人向けの攻略方法


sihui.ioより


つっつきボイス: 「いっぺんに読もうとすると挫折するので最初に全体像を把握しよう的なアドバイスですね」「まーでもわかる: 最近のRailsガイドは情報てんこ盛りでガイドという感じでなくなりつつあるかなぁ」

モブプログラミング


codeclimate.comより

codeclimate.comの2014年の記事です。公式サイトには来年4月にマサチューセッツ州でカンファレンスもあるそうです。


つっつきボイス: 「ペアプログラミングの次はモブプログラミング」「モブプロって、書いている人は自分の意見を交えないルールだったかな」「集団二人羽織的な?」

参考: モブプログラミング - Woody Zuill氏とのインタビュー

Ruby trunkより

Kernel#ppが2.5で標準に

11月のウォッチでお伝えしたKernel#ppがその後本採用になっていました。

net/protocol、net/smtp、tempfile、tmpdirを誰もメンテしないなら自分がやる

_ko1さん激賞のnormalpersonさんです。


つっつきボイス:net/protocolって初めて見た」

参考: Ruby HTTPクライアントの比較表

Ruby

awesome-ruby.com: 定番gemまとめ情報


markets/awesome-rubyより

1ページに全部書いてあるところが便利そうです。
同じ名前のニュースサイトがあって少々紛らわしいですが。

Light Cable: Railsなしで使えるActionCable実装

# 同リポジトリより
Rack::Builder.new do
  map '/cable' do
    # You have to specify your app's connection class
    use LiteCable::Server::Middleware, connection_class: App::Connection
    run proc { |_| [200, { 'Content-Type' => 'text/plain' }, ['OK']] }
  end
end

つっつきボイス: 「こういうAC実装が出てくるのは理解できる: Rackだけ使いたいときとか」「例のEvil Martiansがスポンサーになってますね」

Rubyからsymbolをなくせるか(Ruby Weeklyより)

# 同記事より
{"foo" => 1}[:foo] == 1 # trueだったらいいのに
{foo: 1}["foo"]    == 1 # trueだったらいいのに

つっつきボイス: 「だからHashWithIndifferentAccessが欲しくなる」「記事で引用されてるこれほんに↓: SmalltalkだとSymbolはStringを継承しているのにRubyはそうじゃない」

https://twitter.com/krono/status/916402697183535106

Rubyコードを関数型プログラミングっぽく書いてみた

# 同記事より
module APIDataCommons
  extend self

  def band_names(data)
    user_data(data)
      .fetch('favorite_bands')
      .map { |b| b['name'] }
  end

  def name(data)
    user_data(data).fetch('name')
  end

  private
    def user_data(data)
      data.fetch("user")
    end
end

つっつきボイス: 「あまり関数型っぽいコードには見えないかな?: あえて言うならmethod chainingをふんだんに使ったPromise的なコード」「社内Haskell勢のツッコミが待たれる」

JavaScript: 5分でわかるPromiseの基礎(翻訳)

Rubyデザインパターンとサンプルコード総ざらえ

説明は抑えめで、図とRubyコード中心です。


bogdanvlviv.github.ioより

class Task
  attr_accessor :name, :parent

  def initialize(name)
    @name = name
    @parent = nil
  end

  def get_time_required
    0.0
  end
end

つっつきボイス: 「1ページに収まっているので辞書的に便利そう」

JSON仕様「RFC 8259」と「ECMA-404 2nd Editon」リリース、UTF-8必須に


つっつきボイス: 「今話題のやつ」「404だとNot Foundに見えてしまうと誰かツイートしてた」「RFC 8259の方もどことなく蟹さんマークのNICチップっぽい名前🦀」


卜部さんがこの仕様を元にすごい勢いでJSONパーサー作ってました。

Rubyでリサジュー曲線


つっつきボイス: 「何だか懐かしい感」「リサジュー曲線を見たのがとても久しぶりだったので」

参考: リサジュー図形

ずっと「リサージュ」と思い込んでました(´・ω・`)

SQL

Postgres Weeklyも1月までお休みだそうです。

PostgreSQL 10の互換性のない変更点(Postgres Weeklyより)

記事の日付は10リリース前の「16 May 2017」ですが、リリースノートと見比べるときによさそうです。


つっつきボイス: 「これは見ておくべき情報!」「ありがたい🙏」

PostgreSQLのインデックス(Postgres Weeklyより)


citusdata.comより


  • B-Tree
  • Generalized Inverted Index (GIN)
  • Generalized Inverted Seach Tree (GiST)
  • Space partitioned GiST (SP-GiST)
  • Block Range Indexes (BRIN)
  • Hash

つっつきボイス: 「これも大事っすね: B-Treeで間に合うことが多いけど、データの種類や性質に応じたインデックスを選ばないとインデックスろくに効かなくなったりする」

俺のPostgreSQLチートシート(Postgres Weeklyより)


つっつきボイス: 「チートシートというほど網羅的ではないかな」「『俺のチートシート』ですね」「ポスグレって\で始まるコマンド体系がとっつき悪くって」「sudo -u postgres createuser --interactiveみたいに、名前にpgが入っていないcreateuserとかがシステム系コマンドっぽく見えてしまうのも残念」
「正直、MySQLのコマンド体系の方が親切だった分、PostgreSQLの普及が遅れた気がします」「まあ慣れればぽすぐれの方がコマンド短いから入力速いし: 結局ググるけどな!」

JavaScript

GrimmerとReactを公平に比較してみた

<!--元記事より-->
<button onclick={{action setRandomAnimal}}>Set Random Animal</button>
<ul>
  {{#each randomAnimals key="@index" as |animal| }}
    <li>{{animal}}</li>
  {{/each}}
</ul>
// 元記事より
import Component, { tracked } from '@glimmer/component';

const animals = ["Cat", "Dog", "Rabbit"];

export default class extends Component {
  @tracked randomAnimals = [];

  setRandomAnimal() {
    const animal = animals[Math.floor(Math.random() * 3)];

    this.randomAnimals = this.randomAnimals.concat(animal);
  }
}

つっつきボイス: 「GrimmerだとVue.jsっぽく書けるのか: コンパクトなのはちょっとよさそう」

npmパッケージを自作する(JavaScript Liveより)

{
  "name": "masks-js",
  "version": "0.0.1",
  "description": "A NPM package that exports functions to mask values.",
  "main": "build/index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/brunokrebs/masks-js.git"
  },
  "keywords": [
    "npm",
    "node",
    "masks",
    "javascript"
  ],
  "author": "Bruno Krebs",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/brunokrebs/masks-js/issues"
  },
  "homepage": "https://github.com/brunokrebs/masks-js#readme"
}

つっつきボイス: 「npm作るコマンドとかあるのでgem作るのと同じぐらいの感覚: ↑こういうdescription書くのが面倒だけど」「gemspecもいろいろ書かないといけないですしね」

CSS/HTML/フロントエンド

HTTP Early HintsがRFC 8297に

Early Hintsの生みの親のkazuhoさん自らのツイートです。心なしかアバターが微笑んで見えます。

アクセシビリティのテストツール

aXepa11yGoogleChrome accessibility-developer-toolsなどを紹介しています。

子要素にフォーカスしたまま親要素を表示する

See the Pen :focus-within helpful a11y thing by Chris Coyier (@chriscoyier) on CodePen.

フロントエンドテクの紹介記事です。上のCodePenでマウスオーバーするとわかります。

Firefox Quantumが速くなった理由


hacks.mozilla.orgより


つっつきボイス: 「FirefoxというかMozilla組の追い上げ半端ないですね」「Mozilla Foundationそのものは緩く統括しているだけですけどね」

参考: 爆速進化したブラウザ「Firefox Quantum」は何がどう変化したのか?

その他

GeForce/TITANのデータセンター利用について


https://twitter.com/kunihirotanaka/status/943254857418399744

来年2月にChromeに広告ブロック機能を実装


リモートつっつきボイス: 「Googleが広告ブロック機能を提供しちゃうのか...」

CVEは誰でも出せる

番外

英米の名門校がずらり

体重も測れる超小型計測センサー

もしかしてエネルギー問題解決?

10平方ミクロン程度のグラフェン(原子一個分の薄さの黒鉛)から、腕時計を駆動できるほどの電力が得られる可能性があるそうです。

なお、グラフェンの製造が難しくて研究が遅れていたのが、あるとき黒鉛にセロテープを貼って引っぺがすだけで簡単に作れることがわかって一気に研究が進んだそうです。

参考: 驚異の素材グラフェンの「ゆらぎ」が、無尽蔵のクリーンエネルギーを生むかもしれない:米研究結果

これは凄い


つっつきボイス: 「おおぉ」「MIDIキーボードって実はこういうことするのにとても向いていますね」「物理コントローラが豊富にあるし」「MIDIもプロトコルとして成熟してるし」

藁で作った創作動物

https://layer13.tumblr.com/post/168746265269/ithelpstodream-in-northern-japan-the-wara-art


今週は以上です。

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

週刊Railsウォッチ(20171215)Ruby 2.5.0-rc1リリース、Ruby 2.4.3セキュリティ修正、Ruby 3.0で変わるキーワード引数、HTML 5.2 RECリリースほか

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

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

Rails公式ニュース

Ruby Weekly

Awesome Ruby

RubyFlow

160928_1638_XvIP4h

Postgres Weekly

postgres_weekly_banner

Frontend Weekly

frontendweekly_banner_captured


CONTACT

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