週刊Railsウォッチ(20180709)Rails Developers Meetup Day 3 Extreme今週末開催、RailsのSTI/キャッシュ/添付ファイル/Redis/PDF出力、ECMAScript 2018、プロフェッショナルIPv6ほか

こんにちは、hachi8833です。年々夏が苦手になっています。

各記事冒頭には⚓でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
ウォッチを継続するためにも皆さまからのフィードバックをぜひお待ちしています。@hachi8833までどうぞ🙇

臨時ニュース: Rails Developers Meetup 2018 Day 3 Extremeが7/14(土)開催

何とkamipoさんにActive Recordの質問を出せるそうです。

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


つっつきボイス: 「ややこしいんですが、『先週の改修』という見出しは月曜公開時点で真になるので、つっつきの日である木曜日の今の時点では今週の改修ということになります😅」

STIでのActiveRecordオブジェクト割り当てを高速化

このコミットはActive Record(AR)オブジェクトの同質なリストのアロケーションを高速化する。結果セットにSTIカラムが含まれていることはすべてのARオブジェクトを初期化する前に知ることができるので、今回の変更では「結果セットにSTIカラムがあるか?」というテストを加えて特殊なインスタンス化関数を用いている。こうすることでSTIカラムのチェックをN回ではなく1回で済ませられる。
今回の変更にはデータベースから得たARオブジェクトのアロケーション時に使う初期化関数も新たに導入した。これにより、ARインスタンスごとにハッシュを1つアロケーションせずに済むようになった。
同PRより大意

Before:

[aaron@TC activerecord (master)]$ be ruby -I lib:~/git/allocation_tracer/lib speed.rb
Warming up --------------------------------------
                find     5.000  i/100ms
Calculating -------------------------------------
                find     56.192  (± 3.6%) i/s -    285.000  in   5.080940s
After:

[aaron@TC activerecord (homogeneous-allocation)]$ be ruby -I lib:~/git/allocation_tracer/lib speed.rb
Warming up --------------------------------------
                find     7.000  i/100ms
Calculating -------------------------------------
                find     72.204  (± 2.8%) i/s -    364.000  in   5.044592s
# activerecord/lib/active_record/persistence.rb#L80
+      def instantiate_instance_of(klass, attributes, column_types = {}, &block)
         attributes = klass.attributes_builder.build_from_database(attributes, column_types)
-        klass.allocate.init_with("attributes" => attributes, "new_record" => false, &block)
+        klass.allocate.init_from_db(attributes, &block)
       end

つっつきボイス: 「(今回の社内つっつき初参加者🔰へ)これはtenderloveことAaron Pattersonさんのコミットですね: この方はGitHubの中の人かつRubyとRailsの両方のコミッターです」「そんな凄い人がいるんですね…😲」「ウォッチつっつきにちょくちょく参加しているととこうした事情にもだんだん慣れてきますよ😋」

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

「(初参加者へ)ところでSTI(Single Table Inheritance)ってご存知です?」「いやー…😅」「あ、ご心配なく❤️つっつき会は気楽な集まりなんでわからないこととか知らないことはどんどん聞いてくださいね😋」「😃」「😃」

参考: Active Record の基礎 2.2 スキーマのルール| Rails ガイド — STIに少しだけ言及

「初参加の皆さんが入社する前の社内勉強会『エンタープライズアプリケーションアーキテクチャパターン』でSTIを説明したことがあったのでG-Suiteからスライドを引っ張り出してみるか(作っといてよかったー😉): これこれ↓、STIはデータの持ち方のひとつで、要は継承関係を持つデータを(個別のテーブルではなく)1つのテーブルにまとめてそこにマッピングするという手法です」「おー」



「メリット/デメリットはスライドにも書いてあるとおりですが、RailsはこのSTIをデフォルトでサポートしているので、ActiveRecordのモデルを普通に継承して使うとこのようにSTIとしてデータを持ちます: typeフィールドにそのクラス名が入るとか」「😃」

「この書籍では他にもClass Table Inheritance(クラステーブル継承)パターンやConcrete Table Inheritance(具象テーブル継承)パターンなんかも紹介されてますので、後で社内スライドをどぞ😎」「はいー😀」

「どうやら改修箇所のこの辺↓がSTIっぽいかな: コードだけざっと見たところでは以前はイニシャライザが継承の数だけ呼ばれてたのかも」「『privateにつき呼んではならない』ってありますね😆」

# activerecord/lib/active_record/persistence.rb#L68
       def instantiate(attributes, column_types = {}, &block)
         klass = discriminate_class_for_record(attributes)
+        instantiate_instance_of(klass, attributes, column_types, &block)
+      end
+
+      # Given a class, an attributes hash, +instantiate_instance_of+ returns a
+      # new instance of the class. Accepts only keys as strings.
+      #
+      # This is private, don't call it. :)
+      #
+      # :nodoc:
+      def instantiate_instance_of(klass, attributes, column_types = {}, &block)
         attributes = klass.attributes_builder.build_from_database(attributes, column_types)
-        klass.allocate.init_with("attributes" => attributes, "new_record" => false, &block)
+        klass.allocate.init_from_db(attributes, &block)
       end

RedisCacheStoreのincrement/decrementexpires_inオプションを追加

# 同PRより
irb> Rails.cache.increment("my_counter", 1, expires_in: 100)
1
irb> Rails.cache.data.ttl("my_counter")
=> 99
# skip set expire when "my_counter" has ttl
irb> Rails.cache.increment("my_counter", 1, expires_in: 200)
2
irb> Rails.cache.data.ttl("my_counter")
=> 98

つっつきボイス: 「100とか200は秒なんでしょうね」「ChangeLogにそう書かれてますね: 普通にありそうな機能だけど今までできなかったとはねー😌」

Railsガイドのセクション編成が変更

「Digging Deeper」の一部を「Other Components」に移したそうです(左が現状、右が変更後)。


同PRより


つっつきボイス: 「実は今個人的にYassLabさんとRailsガイドの5.1対応翻訳を進めているところで、ガイドの編成が変わるとそれなりに影響があるので」「こうやってガイドが充実するというのはいいですね❤️: フラットに増えると読みづらくなるしこうやってセクション分けしてもらった方がいいし」


yasslab.jpより

直接関係ありませんが、#33270で「コマンドラインガイドが冗長すぎるのでもっとmanページっぽく簡潔に書いて欲しい」というリクエストを見かけました。


つっつきボイス: 「そこのバランスも考えちゃいますね🤔: 初心者ほど言葉を尽くして書いて欲しいだろうし、慣れてくるとそれが邪魔になってきたりするし」「慣れてきたら--help付けて実行するでしょうね」「それにたとえばrails generateとだけ打てばサブコマンドが表示されますし😋」

「ガイドのDigging DeeperのあたりはRailsチュートリアルやってからの方がいいんでしょうか?」「それはあるかも: チュートリアルにはひととおり盛り込まれているので、そこでキーワードを押さえておいてからこういうページを眺める方が入りやすいかもですね😉」「とはいうもののRailsチュートリアルには実際に使わない機能もいっぱい盛り込まれているので無理して片っ端から機能を使おうとしなくてもいいですよ😆」「😆」

#has_secure_passwordの属性名を設定可能に

# activemodel/test/cases/secure_password_test.rb#L185
   test "authenticate" do
     @user.password = "secret"
+    @user.activation_token = "new_token"

     assert !@user.authenticate("wrong")
     assert @user.authenticate("secret")
+
+    assert !@user.authenticate_activation_token("wrong")
+    assert @user.authenticate_activation_token("new_token")
   end

つっつきボイス: 「なるほど、パスワードがあるかどうかをチェックするメソッドが今まではRails側で決め打ちだったのを変更できるようにしたと: この修正ならそれだけのために自分でメソッド再定義とかしなくて済む😋」「😃」「そんなに頻繁に使う機能ではなさそうですけどね😉」

retry_on/discard_onに例外を複数渡せるようにした

# activejob/lib/active_job/exceptions.rb#L45
-      def retry_on(exception, wait: 3.seconds, attempts: 5, queue: nil, priority: nil)
-        rescue_from exception do |error|
+      def retry_on(*exceptions, wait: 3.seconds, attempts: 5, queue: nil, priority: nil)
+        rescue_from(*exceptions) do |error|
           if executions < attempts
-            logger.error "Retrying #{self.class} in #{wait} seconds, due to a #{exception}. The original exception was #{error.cause.inspect}."
+            logger.error "Retrying #{self.class} in #{wait} seconds, due to a #{error.class}. The original exception was #{error.cause.inspect}."
             retry_job wait: determine_delay(wait), queue: queue, priority: priority
           else
             if block_given?
               yield self, error
             else
-              logger.error "Stopped retrying #{self.class} due to a #{exception}, which reoccurred on #{executions} attempts. The original exception was #{error.cause.inspect}."
+              logger.error "Stopped retrying #{self.class} due to a #{error.class}, which reoccurred on #{executions} attempts. The original exception was #{error.cause.inspect}."
               raise error
             end
           end
         end
       end

つっつきボイス:exception*exceptionsになったのか」「あー、retryのたびに少しずつ異なる例外が発生するというのはありうるから、それをまとめて渡せるようにしたということね」

「そしてこれはActiveJob」「ActiveJobはジョブ制御のラッパーという理解で合ってます?」「そのはずです: 後ろで動かすのはSidekiqとかDelayed_jobとかResqueあたりが多いです」

非同期処理には本質的にワーカーが必要になります: たとえば巨大なCSVを生成して完了したらダウンロードリンクを作るみたいな時間のかかる処理はフロントのWebサーバーではできないので、それとは別にワーカープロセスを立ち上げてそこにジョブを投げるという形を取る」「ActiveJobはそういう非同期ジョブを扱うもので、そのバックエンドで動くミドルウェアがいろいろあり、それをどう使い分けるかですね」

「一番メジャーで実績があるのはおそらくSidekiqかResqueあたりかな: Delayed_jobはもう少し古くて実装もちょっとしょぼい😆」

「SidekiqやResqueだとその背後にさらにRedisという機能豊富なKVS(Key-Value Store)があってジョブのプッシュ通知なんかをそのRedisでサポートしている」「これを使うとジョブを投げたら待ち構えていたワーカーがすぐそれを動かすなんてこともできる」「SidekiqやResqueはRedisのおかげで、ジョブの優先順位付けやリトライ処理とか、重いジョブ/軽いジョブに応じて複数キューを使い分けるようなより高度な処理とかもできる: たとえば有料会員だけキューを別にしてジョブにリソースを多く割り当てるとか」「アダルトサイトなんかにありそうなやつですね🤣」「ま、どこでもやってる機能ですね: YouTubeとかG-Suiteとかもそうですし」

「ただねー、そのためにはRedisを立ち上げて常駐させないといけないわけですよ😓」「😆」「すると今度はRedisが死んでないかどうか確認したりとかRedisのバックアップが必要になったりとか、そっちの手間がかかる😂」

「逆にDelayed_jobはRedisではなくデータベースに専用のテーブルを作って保存するので既存のデータベースに乗せればそういう手間がかからないのが利点: その代りデータベースに定期的に5秒に1回とかポーリングかけたりするので実装の効率はよくない😭」「なるほど、用途に合わせてどれにするか検討すると🤔」

「Redisって思った以上にいろいろやれるヤツだったんですね😲」「実際Redisは当初はキーバリューストアとして出発したのがその後機能がいろいろ追加されてきたので今や単なるキーバリューストアとは言い切れないですね💪(PostgreSQLほどではないにしても)」「ふーむ」「なのでRedisっていろんな使い方ができるし、どの機能を使っているかによって将来Redisを別のミドルウェアに置き換えるときの選択肢も違ってきます」「なるほど!😃」


redis.ioより

参考: Active Job の基礎 | Rails ガイド

ドキュメント更新: OS XをmacOSに置き換え


つっつきボイス: 「TechRachoをやっているうちにいつの間にか呼び名がmacOSって変わってて当時おやって思いましたね」「OSの名前が猫さんシリーズというかネコ科の動物シリーズでなくなったあたりで変わった気がする?」

参考: macOS - Wikipedia

さらに、2016年にリリースされたmacOS Sierraより、iOSなどアップルの他のOSの名前との親和性を図るため、「OS X」から「macOS」へと改称された
Wikipediaより

Rails

fie: RailsのWebSocket接続上で動くフロントエンドフレームワーク(Ruby Weeklyより)


fie.eranpeer.coより

同リポジトリより

特徴:

  • 3-wayデータバインディング
  • HTMLバインディング(DOMイベント用)
  • deep nested構造のサポート
  • pub/subが組み込み済み
  • isomorphicな作りでJavaScriptへの依存をほぼ排除可能
  • 開発期間の短縮

つっつきボイス: 「ふんふん、TurboLinksを使ったり…おーっと、Opal使ってるぞこれ😲!」「OpalってRubyをJavaScriptに変換するアレか」「Opalってproductionでどのぐらい使われてるんだろか?😅OpalってRubyのコードを1対1対応的にJavaScriptのコードに置き換えるかなり泥臭いというか力技なやつ」「アセンブラみたいな」「RubyとJavaScriptってIntegerやStringの扱いに違いがあるからOpalもそういう部分で動かなかったりすることもあるわけで: ともあれこのfieはJavaScriptなしでRubyだけで書けるぜということか」「人類の夢🚀」「なかなかアツい: 面白そうなのは間違いないっすね😀」「😆」


opalrb.comより

isopmorphicというと数学の「同型写像」かな?っと思ったら、Opalの力でRubyがJavaScriptと同じように動くということのようです。

参考: 同型写像 - Wikipedia

PaperclipからActive Storageへの移行を安全に行う(Ruby Weeklyより)

↓Paperclipの移行ガイド(翻訳済み)が既にありますが、それよりもっと詳しく書かれているそうです。

Rails: PaperclipからActiveStorageへの移行ガイド by thoughtbot(翻訳)


つっつきボイス: 「初めての人🔰もいるので説明しておくと、PaperclipはRailsで添付ファイルを扱うのによく使われてたんですが、Rails 5.2でActive Storageという同じ機能↓が公式に導入されたんですね」「でPaperclipはその後開発が終了したので上の移行ガイドが開発元のThoughtBotから出されました」

Rails 5.2を待たずに今すぐActiveStorageを使ってみた(翻訳)

「Webアプリでの添付ファイルの扱いってRailsに限らずなかなか面倒で、たとえばアップロードのフォームの後に確認画面を追加するだけで一気に面倒になる」「おー😲どの辺が面倒に?」「添付ファイルってフォームをPOSTするときにアップロードされるんで、確認画面がなければアップロードしてバリデーションすればおしまいなのに、確認画面があると一部のデータでバリデーションエラーが起きて戻ったフォームに、あたかもさっきと同じ添付ファイルが残っているかのように再表示したいじゃないですか: でもエラーの場合はまだデータベースに添付ファイルがsaveされてなくてそのままだと添付ファイルが再表示されない😓なのでいろいろ工夫しないといけないとか」

「その場合フロント側のJavaScriptでどうにか再表示することになるんでしょうか?」「いや、結局サーバー側に一度は一時的に保存しないといけなくなることが多いですね: 他にも、再アップロードしたときに一度目のアップロードファイルをIDを頼りに正確に取り出さないといけなくなったりとか、Webアプリでは誰しも一度はやる作業なんですけど本当に面倒😭」「ActiveStorageはそういうところも一応やってくれます😋」「😃」

Railsのフラグメントキャッシュを分解調査する(Ruby Weeklyより)

珍しくつっつきより先に翻訳公開しました。

Railsのフラグメントキャッシュを分解調査する(翻訳)


つっつきボイス:st0012さんがこの記事を書いた動機のひとつが、フラグメントキャッシュについての情報が意外にネット上に見当たらないからだったそうです」「たぶんフラグメントキャッシュってインターフェイスも含めて昔からほとんど変わってないからじゃないかな?🤔フラグメントキャッシュそのものは割と普通のキャッシュ」「😃」

「Railsだと他にもロシアンドールキャッシュっていう、普段表に出てこないキャッシュもありますけどフラグメントキャッシュとどんな関係でしたっけ?」「ロシアンドールキャッシュの末端がフラグメントキャッシュ」「なるほど😃」

「Railsのキャッシュはいくつかの階層になっているんですが、フラグメントキャッシュはその中のひとつで、たとえば以下のようにcache なんちゃらと書くことで範囲を指定し、そこがキーになって、キーが変わらない限りキャッシュから返すようになり、更新されていれば再レンダリングするというものです」「ふむふむ」「まあ他の言語とかフレームワークでも似たようなことはやっているはず」

<% cache project do %> 
  <b>All the topics on this project</b>
  <%= render project.topics %>
<% end %>

「そしてRailsのキャッシュの賢いところは、キャッシュを入れ子にしたときに、入れ子の外側が更新されたら内側のキャッシュも全部廃棄して再レンダリングし、入れ子の内側だけが更新された場合は外側は更新せずにこれまでどおりキャッシュを返せることで、これがロシアンドールキャッシュですね」「キャッシュが入れ子になっていれば自動でよしなにやってくれるということか」「そうそう」

「ただ、キャッシュはあまり気軽に使うとはまります: 特にパフォーマンスが要求される箇所でもないのにむやみにキャッシュすると後で自分の首を締めることになるかもしれないので😇自分は必要がない限り使わないですね」「😵」「それはたとえば画面が更新されるべきときに更新されないとか?」「他にもキャッシュで他人のデータが表示されたりするとか、とってもよくあるパターン🕶」「😲」

「Railsでない素のCSSなんかでも、更新したのにキャッシュに反映されなくてはまるなんてよくありますね」「キャッシュは実は難しいです: 上でいうとprojectが更新されれば当然キャッシュも更新されますが、projectの下にたとえばusersなんてリストがあったときにそちらが更新されない、なんてことがあったりする😭そういうときはusersが更新されたときにprojectに明示的にtouchするとかして更新しないといけなくなったり」「😲」「Railsのキャッシュはそれなりに賢くできてますが、そういうわけでこれに全面的に頼るのはどうかなーと思うわけです: キャッシュを使うのは遅くなったときぐらいで」「😃」

参考: Rails のキャッシュ – ロシアンドールキャッシュ: 概要 | Rails ガイド

ガイドからの写しですが、Rails 3まであった「ページキャッシュ」と「アクションキャッシュ」はRails 4からgemに切り出されてデフォルトでは含まれなくなりました。

RailsでのStripe支払いを管理する(Ruby Weeklyより)

↓TechRachoでも一般的なStripe記事を公開しました。

Stripe決済を自社サービスに導入してわかった5つの利点と2つの惜しい点


つっつきボイス: 「決済代行サービスのStripe、BPS社内でもどんどん使われ始めてますね」「Stripeのいいところは、公式ドキュメントが非常にしっかりしていることと、Rubyのコードもあること: そういえばRubyKaigi 2018にもStripeの人が来てたと思うけど↓、もしかするとStripeってRailsで書かれてるんじゃないかな?なんてね」「ありそう」「Stripeは問題なく実装できるいいヤツ❤️」

参考: A practical type system for Ruby at Stripe. - RubyKaigi 2018
参考: A practical type system for Ruby at Stripe. - mactkg-pub — セッションのメモです


stripe.com/より

breezy_pdf_lite-ruby: HTML->PDF変換サービスのRubyバインディング(Ruby Weeklyより)


breezypdf.comより


つっつきボイス: 「最終的にChromeでレンダリングさせてるみたいです」「そうそう、この種の変換はだいたい裏でヘッドレスブラウザを立ち上げてやってますね: html2pdfあたりは独自のエンジンを持ってたような気がするけどどうだったかな…」

「ま、HTMLからPDFを作成するだけなら意外と簡単です😎普通の紙に印刷して人間が読めればそれでいいので、プリント用CSS@media print)を書くのが実は編集も含めて圧倒的に楽😋」「😃」

「一方、専用の帳票に印刷するための本格的なPDF帳票(宅配便の帳票出力↓とか)なんかを作ろうとすると一気に大変になる: インチ単位とかmm単位で座標を合わせないといけないし、文字が帳票からはみ出たりとか、特定のフォントファイルを使わないといけないとか、ページまたぎの処理が面倒とか、もろもろ大変😭」「😆」

「確か日本製の帳票PDF作成gemでおすすめしてたのありましたよね?」「あーThinReportsですね: これはかなり優秀で、GUIのエディターがついているのがとてもエライ💪」「😃」


thinreports.orgより

「そういう帳票作成の実装って、たいてい帳票を定規で測って印刷しては神微調整を繰り返すみたいな古典的な作業になっちゃうんですね: あれはつらい🤮」「😭」「古典的なペーパーフィード付きのドットインパクトプリンタ↓って、帳票のために長らく使われてましたよね」「今でもカーボン紙なんかのために現役で使われてます: 宅急便の会社によっては帳票枠なしの普通のPDF印刷に移行したところもあるみたいですが」

↑何だか曲を演奏してます。

11月開催のRubyWorld Conference 2018情報

だいぶ先になりますが、RubyWorld Conference 2018のお知らせです。参加登録は現在準備中です。

その他Rails

Ruby trunkより

signal.cでバッファオーバーフロー

# signal.c#L262
     if (prefix_ptr) *prefix_ptr = prefix;
+    left_len = len - prefix;
     for (sigs = siglist + !exit; sigs->signm; sigs++) {
-   if (memcmp(sigs->signm, nm + prefix, len - prefix) == 0 &&
+   if (left_len != strlen(sigs->signm)) { continue; }
+   if (memcmp(sigs->signm, nm + prefix, left_len) == 0 &&
        sigs->signm[len - prefix] == '\0') {
        return negative ? -sigs->signo : sigs->signo;
    }

つっつきボイス: 「C言語で普通によくあるメモリ範囲のあふれみたい🕶」

-DMJIT_FORCE_ENABLE=1が動かない

k0kubunさんが「RubyBenchの後で見てみるのでそれまで無視で」と返信付けてました。

# 同issueより再現コード
ruby --jit-wait --disable=gems -e '1000.times { a, b = nil }'
# または
ruby --jit-wait --disable-gems -e '1000.times { break if /a/ =~ "ab" && !$~[0] }'

追伸: その後#63875でk0kubunさんによって修正されました。

Pathname#joinの挙動がFile.joinと異なる

# 同issueより
Pathname.new('/a').join('/b').to_s
# => "/b"
File.join(Pathname.new('/a'), '/b').to_s
# => "/a/b"

つっつきボイス: 「あーこれねー😅、Pathname.newだと/bみたいにスラッシュを付けてjoinした時点で/bだけになっちゃうと: 普通はjoinの引数には変数が置かれるだろうし、ちょっとつらい」「RailsだとFile.joinの方がよく使われてたように思うけど、挙動を揃えて欲しいというのは分かりみある」

Ruby

Rubyのメモリ設定でスラッシングを防ぐ(Ruby Weeklyより)

RubyKaigi 2018で見ました❤️。


つっつきボイス: 「TechRachoの翻訳記事↓でお馴染みのRubyチューニングの鬼Noah Gibbsさんです: 昨年の広島のRubyKaigiで何度も見かけたのに気づけなかったので、今年やっとお礼を伝えられました😀」「チューニングお世話になってます🙇」「スライドをすごく簡単にまとめると、mallocじゃなくjemallocを使おう、環境変数はしっかり設定しよう、自作のEnvMemというgemはチューニングに便利、という感じです」

米国から見た日本のRuby事情(翻訳)

「しかしスラッシングになるとカーネルパラメータとの絡みもあるからなー」「そういえばスラッシングと断片化ってまた違うんでしょうか?」「そうですね、一般的には、断片化が進んだ結果、本来ならばひとかたまりのデータなのにあちこちから読み出さなければならなくなって遅くなった状態をスラッシングって言いますね」「なるほど!😀」「そういえば情報処理技術者試験にスラッシング出てました😋」「そうそう、一般にはスワップ処理なんかで出てきますね☺️」

参考: スラッシング - Wikipedia

「ところで実物のNoah Gibbsさんの話す英語、自分史上最大ぐらいに早口だったのでもうスライド画面が頼りでした😅: TechRachoでRubyメモリ関連の記事を翻訳してなかったらマジでついていけなかったかも」「RubyKaigiはRubyの非常にコアな部分に関する発表がとても多いので、TechRacho記事のこの辺↓とか読んで予習しとかないと大変ですね😎」「もっともっとー😂」

Ruby: mallocでマルチスレッドプログラムのメモリが倍増する理由(翻訳)

Rubyのヒープをビジュアル表示する(翻訳)

RubyのForwardableでメソッドを委譲(Ruby Weeklyより)


つっつきボイス:ForwardableはRuby標準の委譲ライブラリだそうです」「委譲は普通に使うけどこれは知らなかったー」「社内の方で確か知ってた人いました」「やるなー🕶: def_delegatorsなんてのがあるし↓」「これはRuby Goldの試験にも出なかった?」「…出てなかったかも…」

# 同記事より
module Decorator
  class StudentDecorator
    extend Forwardable

    def_delegators :@student, :first_name, :last_name, :professors, :birthday, :course
    def_delegator '@student.course', :name, :course_name 

    def initialize(student:)
      @student = student
    end

    def full_name
      "#{@student.first_name} #{@student.last_name}"
    end

    def professors_names
      @student.professors.map(&:name).join(', ')
    end
  end
end

参考: るびま0012号 標準添付ライブラリ紹介 【第 6 回】 委譲公式ドキュメントの内容もるびまに委譲されてます。

Rydux: ReduxをRubyで実装(Ruby Weeklyより)

# 同リポジトリより
require 'rydux'

class UserReducer < Rydux::Reducer
  @@initial_state = { name: 'Alex', age: 20 }

  def self.map_state(action, state = @@initial_state)
    case action[:type]
    when 'CHANGE_USER_NAME'
      state.merge(name: action[:payload][:name])
    else
      state
    end
  end

end

Store = Rydux::Store.new(user: UserReducer)

class Friend
  def initialize
    Store.subscribe(self)
    @users_name = Store.state.user.name
  end

  def state_changed(state)
    @users_name = state.user.name
  end

  def greet_user
    puts "Hello, #{@users_name}"
  end
end

# Create a new friend (this will subscribe it to the store)
friend = Friend.new
friend.greet_user #=> Hello, Alex

# Change a value in the store
Store.dispatch(type: 'CHANGE_USER_NAME', payload: { name: 'Mike' })
friend.greet_user #=> Hello, Mike

つっつきボイス: 「Rydux!発音はライダックス?リダックス?」「やっぱりステート管理欲しいんですね: Vue.jsにも状態管理があるぐらいだし」「JavaScriptはこういうライブラリがないとステートがマジでわけわからなくなるから欲しくなると思うけど、Rubyには果たして必要かなー?とは思う🤔」「たとえばサーバーサイドレンダリングをやってればこういうのが欲しくなるかもしれないけど、普通のビジネス系のデータはデータベースに入れるからあまり複雑なステートを使う機会がない気がする」「😃」「SPAなんかでどうしてもサーバー側でレンダリングしたい!みたいなときなら要るのかもしれないけど、そんな状況ってあるのか?」「😆」「😆」

参考: シングルページアプリケーション - Wikipedia

Reduxストアの概念をRubyで再実装して理解する(翻訳)

ビジネスルールもオブジェクト(RubyFlowより)

Service Object反対派のAvdi Grimm氏の動画付き記事です。

Rails: Service Objectはもっと使われてもいい(翻訳)


つっつきボイス: 「これは割と基本的な記事かなー: 何とかRuleみたいなクラスを作ってそれをDIするみたいな」「Strategyパターン的な」

class MemberEligibleForTierRule
  attr_reader :member, :tier

  def initialize(member:,tier:)
    @member, @tier = member, tier
  end

  def satisfied?
    (((member.miles + member.qualifying_partner_miles) >= tier.required_miles) ||
     (member.segments >= tier.required_segments)) &&
      (member.dollars >= tier.required_dollars)
  end
end

Rubyアソシエーション開発助成成果報告会(終了)

ウォッチ公開の頃には終わってますね💦。気づくのが遅すぎました。#ragrantハッシュタグで追えます。

その他Ruby


来年のRubyKaigi会場です。こちらは#rubykaigikaigiハッシュタグで追えます。

参考: RubyKaigiKaigi に行ってきた - 虚無庵 — 「RubyKaigiはCFPを応募すると割引になる」そうです👀👁

クラウド/コンテナ/インフラ/Linux

「プロフェッショナル IPv6」が無料ダウンロード


つっつきボイス: 「おー、あきみちさんの本!: IPv6の知識って学部生以来だから勉強しなきゃ💦」「IPv6っていうとNTTのフレッツのバックボーンとかで使われている印象でした」「NGNですね: ところがですねー、NGNの仕様はIPv6と同じじゃないんですよ」「えー!😲」「NTTのNGNはIPv6の仕様が固まる前に使われ始めたからしょうがないんですが、インターネットのIPv6とNGNではそのまま接続できない」「何だかガラケーの独自HTMLみたいな話ですね😅」

参考: IPv6とNGN | テクノロジーコラム | 情報畑でつかまえて

「(目次を見ながら)変わってないところも結構ありそう、かと思うと知らないものもある…お、ネイバーディスカバリーかいいなー💪、お、『第11章 Path MTU discovery』のあたりとか面白いし、知っておくとネットワークに詳しい感出せるかもですよ😎」「MTU=Maximum Transfer Unit」「MTUは通信路によって異なるんですが、最大でどれぐらい大きなMTUが通るかというのはは調べるしかないので、それを調べるためのアルゴリズムがこのPath MTU discovery」「おー、IPv4だとよくPCのネットワーク設定のMTUいじって大きくするみたいな素人ネットワークチューニング記事を見かけますけど」「MTUが実際に詰まるのはどちらかというとL2つまりイーサネットのフレームサイズ(たとえばすごく古いイーサネットだと確かフレームサイズは1536バイト)で、通信経路に1つでもMTUの小さいルーターやスイッチがあると通らなくなったりします」「そっかー😃」「とにかくPath MTU discoveryのあたりはいろいろ面白いので勉強してみるといいですよ😋」

「『第13章 IPv6エニーキャスト』は日本でも早くから使われてましたね」「ついでにすみません、エニーキャストはマルチキャストとどの辺が違うんでしたっけ?」「あーかなり違いますね: まずマルチキャストは動画なんかの配信が目的で、大勢の人が1つのマルチキャストアドレスを共有すると、そのアドレスに送信した動画データが全員に配信されるというものです」

参考: マルチキャスト - Wikipedia

「エニーキャストの目的はむしろ逆で、同じアドレスを複数ユーザーが共有する点は同じなんですが、全員に届けるのではなく誰か1人に届けばいいというヤツです」「エニーキャストはたとえばDNSとかタイムサーバー(NTPサーバー)なんかに使います: でないと特にNTPサーバーは世界中ですごく沢山の人が同じアドレスを指定したりしているので、エニーキャストしないとたちまちパンクする😇」「どちらかというと分散が目的なんですね」「それもあります: ただし冗長化とは違いますが🧐」「😃」

参考: エニーキャスト - Wikipedia

BOSH: 分散システムのリリース/デプロイ/ライフサイクル管理(Awesome Rubyより)


bosh.ioより

SQL

Google BigQueryの公式インサイド情報


つっつきボイス: 「先週BigQueryが話題に出たので今回そのあたりを見てみました😋」

Google BigQueryとは

参考: なぜ私たちはSumo Logicを捨ててBigQueryを選んだのか - tech.guitarrapc.cóm
参考: BigQueryで150万円溶かした人の顔 - Qiita


つっつきボイス: 「溶かした記事は有名なヤツですね: 記事にもありますけどBigQueryはスキャンしたデータ量で課金されるので、毎回全部readするような非効率なクエリを凄い頻度で実行するとこうなる😇」「BigQueryは普通のSQLと同じに考えない方がいいということでしょうか?」「というよりは課金体系の違いですね: 普通のSQLではそういう課金の仕方はしてないので😉」「なるほど😃」「データセットが極端に大きい時は忘れずに事前に動かして試す方がいいでしょうけど、そうでなければそんなに怖がらなくてもいいと思います😉」「😃」

pgquarrel: PostgreSQLスキーマ比較ツール(Postgres Weeklyより)

# 同記事より
$ pgquarrel --source-dbname=dev --target-dbname=prod --source-host=192.168.0.8 --target-host=192.168.0.6 --function=false --comment=true
--
-- pgquarrel 0.4.0
-- quarrel between 9.1.24 and 10.4
--

CREATE DOMAIN public.cep AS text
    CONSTRAINT cep_check CHECK ((VALUE ~ '^\d{5}-d{3}$'::text));

CREATE TABLE public.bar (
description character varying(30) NOT NULL,
foo_id integer,
id integer NOT NULL
);

ALTER TABLE ONLY public.bar
    ADD CONSTRAINT bar_pkey PRIMARY KEY (id);

ALTER TABLE ONLY public.bar
    ADD CONSTRAINT bar_foo_id_fkey FOREIGN KEY (foo_id) REFERENCES foo(id);

COMMENT ON TABLE public.bar IS 'this is another table';

COMMENT ON COLUMN public.bar.description IS 'this is a column';

ALTER TABLE ONLY public.foo DROP COLUMN removeit;

ALTER TABLE public.foo RESET (autovacuum_enabled);

JavaScript

先週のflutter

参考: JSON and serialization - Flutter
参考: samples/built_complex_object.g.dart at master · flutter/samples

ECMAScript 2018仕様が公開(JavaScript Weeklyより)


ecma-international.orgより


つっつきボイス: 「こうやって仕様が毎年出ると、結局どのバージョンで書けばいいんだ?問題が終わらない😭」「JavaScriptトランスパイラのBabelは真っ先に対応しそうですね」「そうなるでしょうね: ChromeやFirefoxもじきに追従するだろうし、問題になるとすれば更新の止まった古いスマホのブラウザかなー🤔」「ECMAScript 2018で書いても大丈夫になるのはいつだろう…」


babeljs.ioより

参考: Babelを使おう - Qiita

ECMAScriptのプロポーザルを追うサイト(JavaScript Weeklyより)

オフィシャルなんだそうです。


つっつきボイス:TC39は有名ですね: ECMAのタスクフォース的なグループ」

Chrome 69でLayoutNGが登場

[速報] 待望のLayoutNGがやってきた!Chrome 69は見た目も中身も大幅に刷新


同スライドより


つっつきボイス: 「先週のbabaさん速報記事そのままですが💦」

CSS/HTML/フロントエンド/テスト

テスト自動化に関する書籍情報


つっつきボイス: 「何冊か家に本があった気がする」「テスト自動化の難しさは、会社とか案件によってテスト内容がものすごく違うというところにありますねー🤔」「フロント界隈の動向が激しいのも一因でしょうか?」「そこはそれほどでもないです: Seleniumドライバ↓なんかは歴史も長いし」「そっかー😲」「『こういうときはこうする』みたいなテストのノウハウが、案件や組織が異なるとまるで通用しないなんてこともざらにあるので、そこが大変😵」


seleniumhq.orgより

headless chromeでcookieを扱う


つっつきボイス: 「えー、headless chromeにcookie扱うAPIがないのか😲」「page.driver.browser.manage.all_cookiesみたいにすると取れるのね↓😋」

module FeatureHelper
  def cookie_value_from(name:)
    cookies = page.driver.browser.manage.all_cookies
    cookie = cookies.find { |c| c[:name] == name }
    cookie && cookie[:value]
  end

  def add_cookie(name:, value:)
    page.driver.browser.manage.add_cookie(
      name: name,
      value: value.to_s
    )
  end
end

Poltergeistって今も使われてるんでしたっけ?」

終わってたのはPhantomJSの方でした↓。PoltergeistはCapybara向けのPhantomJSドライバです。

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

LayoutIt: CSS Gridレイアウトのインターフェイスビルダー(Frontend Focusより)


同サイトより


つっつきボイス: 「なるほど、こういう縦横で割り切れないいやらしいレイアウト↑なんかをCSS Gridで作れるGUIツールってことか」「コーディングで嫌がられるレイアウト😆」「layoutitってlayoutが動詞になってるし😅」

Feature Policyとは(Frontend Weeklyより)

Googleのドキュメントです。

Feature-Policy: unsized-media 'none'
Feature-Policy: geolocation 'self' https://example.com
Feature-Policy: camera *;

つっつきボイス: 「Feature Policyヘッダーって聞いたことぐらいはあったけどこんなにいっぱいあったとは…😲」「このcameraとかは見たことある😋」

参考: Feature Policy — W3Cの仕様
参考: Feature Policy、ブラウザの特定機能を無効にする仕様 - ASnoKaze blog

言語よろずの間

Rutie: RubyとRustをつなぐ(Ruby Weeklyより)

類似のRuru↓とruby-sysの続編プロジェクトだそうです。


d-unseductable/ruruより

extern crate rutie;

use rutie::{Object, RString, VM};

fn try_it(s: &str) -> String {
    let a = RString::new(s);

    // The `send` method returns an AnyObject type.
    let b = a.send("reverse", None);

    // We must try to convert the AnyObject
    // type back to our usable type.
    match b.try_convert_to::<RString>() {
        Ok(ruby_string) => ruby_string.to_string(),
        Err(_) => "Fail!".to_string(),
    }   
}

#[test]
fn it_works() {

    // Rust projects must start the Ruby VM
    VM::init();

    assert_eq!("selppa", try_it("apples"));
}

fn main() {}

つっつきボイス: 「RubyでRustを使ったり、RustからRubyを使ったりできるみたい」「😲」

termtosvg: ターミナル操作をSVGでキャプチャする(GitHub Trendingより)


同リポジトリより

Pythonで書かれています。READMEのアニメーションもこれで作成されていて、気のせいか文字がぐにゃぐにゃ揺れています。


つっつきボイス: 「SVGでアニメーションができるって初めて知った😲文字の再生ならSVGの方が軽そうだけど」「そのせいか画面がちょっと揺れますね」

参考: UI改善にキラリと役立つ! SVGアニメーションの作り方まとめ - ICS MEDIA

Form: Goのstructでフォーム生成

何だか既視感あります。

// 同リポジトリより
type Address struct {
    Street1 string `form:"label=Street;placeholder=123 Sample St"`
    Street2 string `form:"label=Street (cont);placeholder=Apt 123"`
    City    string
    State   string `form:"footer=Or your Province"`
    Zip     string `form:"label=Postal Code"`
    Country string
}

func main() {
    tpl := template.Must(template.New("").Parse(inputTpl))
    fb := form.Builder{
        InputTemplate: tpl,
    }

    pageTpl := template.Must(template.New("").Funcs(fb.FuncMap()).Parse(`
        <html>
        <body>
            <form>
                {{inputs_for .}}
            </form>
        </body>
        </html>`))
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "text/html")
        pageTpl.Execute(w, Address{
            Street1: "123 Known St",
            Country: "United States",
        })
    })
    http.ListenAndServe(":3000", nil)
}

つっつきボイス: 「しかしこのFormってパッケージ名はひどい🤣」「探しにくすぎるー🤣」

その他

Java11のAPI変更


つっつきボイス: 「Javaってもう11になったのかー」「Java勢の方に思ったけど今日のつっつきにはいなかった💦」「strip()が今までなかったなんて😅」

参考: instance method String#strip (Ruby 2.5.0)

VDIとは

参考: VDI(デスクトップ仮想化)とは | シンクライアントとの違い・サービス比較 - VDI(デスクトップ仮想化) | ボクシルマガジン


つっつきボイス: 「AWSにもシンクライアント的なサービスがあるってこの記事で初めて知りました」「ああAWS WorkSpacesですね↓」「メモリ4GBかー」「ネットワークさえ速ければもの凄いロースペックマシンよりはVDIの方がいいんじゃね?😎」

参考: Amazon WorkSpaces (完全マネージド型でセキュアな仮想クラウドデスクトップ - VDI)| AWS


aws.amazon.comより

「ためしがき」フォント表示チェックサイト

入力すればわかります。


同サイトより

その他のその他

番外

apollo: 自動運転プラットフォーム

同リポジトリより


つっつきボイス: 「Baiduがやってるオープンソースの自動運転だそうです」「とりあえず日本の公道は当面走れないナ😆」「法律が追いついてない😆」

スラッシュvsバックスラッシュ

ダークマターなしでも安定している銀河

定説がひっくり返る瞬間を目にすることができるかもしれないと思うとワクワクします。

参考: 「ダークマターを含まない銀河」の発見が、世界中の宇宙物理学者を驚かせた|WIRED.jp


今回は以上です。

おたより発掘

バックナンバー(2018年度後半)

週刊Railsウォッチ(20180702)Ruby 2.2メンテ正式終了、Ransackがつらくなるとき、書籍『Domain-Driven Rails』、GitHubの高可用MySQLほか

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

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

Rails公式ニュース

Ruby Weekly

Awesome Ruby

RubyFlow

160928_1638_XvIP4h

Hacklines

Hacklines

Postgres Weekly

postgres_weekly_banner

Frontend Focus

frontendfocus_banner_captured

Frontend Weekly

frontendweekly_banner_captured

JavaScript Weekly

javascriptweekly_logo_captured

Github Trending

160928_1701_Q9dJIU

デザインも頼めるシステム開発会社をお探しならBPS株式会社までどうぞ 開発エンジニア積極採用中です! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

hachi8833

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

hachi8833の書いた記事

週刊Railsウォッチ

インフラ

ActiveSupport探訪シリーズ