週刊Railsウォッチ(20170623)gemを見極める7つのコツ、mixinがよくない理由、重いページをrender_asyncで軽減ほか

こんにちは、hachi8833です。嵐が明けてから早くも汗ダラダラです。

それでは今週のRailsウォッチ、いってみましょう。

Rails 5.1.2rcがリリース: バグ修正が主


rubyonrails.orgより

今週頭にリリースされたRails 5.0.4に続き、5.1.x系でもバグ修正が行われます。リグレッションがなければ来週月曜(日本では事実上火曜)にリリースされる予定です。

修正点は5.0.4より多めで、ActionCable/ActionMailer/ActiveJob以外はすべてChangelogに修正・追加が記載されています。

差分: 5.1.1-5.1.2rc1

つっつきボイス:@kamipoさんの修正、今回も多いなー」「@y_yagiさんのもある」

昨日のRailsウォッチつっつき会では、Webチームの新卒メンバーのyumaさんが初参加してくれました。大画面に移されたRailsリポジトリのコミット数やコミット番号の数字の大きさに驚いていたようです。

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

新機能: mailerでデリバリージョブを細かく設定

# actionmailer/lib/action_mailer/base.rb
     helper ActionMailer::MailHelper

+    class_attribute :delivery_job, default: ::ActionMailer::DeliveryJob
     class_attribute :default_params, default: {
       mime_version: "1.0",
       charset:      "UTF-8",

つっつきボイス:deliver_laterで使うActiveJob継承のActionMailer::DeliveryJobでカスタムクラスを使えるようにしたということかな」「ジョブのリトライが失敗した場合の対応とか」「メール送信ってまさしくジョブだな、って改めて思う」

パフォーマンス: mass assignmentの速度を改善

# activemodel/lib/active_model/attribute_assignment.rb
+# frozen_string_literal: true
  require "active_support/core_ext/hash/keys"

  module ActiveModel
      def _assign_attribute(k, v)
-       if respond_to?("#{k}=")
-         public_send("#{k}=", v)
+       setter = :"#{k}="
+       if respond_to?(setter)
+         public_send(setter, v)
        else
          raise UnknownAttributeError.new(self, k)
        end

after 40.172k (± 2.6%) i/s – 203.149k in 5.060347s
before 32.679k (± 4.0%) i/s – 163.929k in 5.025078s

つっつきボイス:setter = :"#{k}="でリテラルをシンボルに変えて高速化してるけど、こういうのをやり始めたらきりがないんではw」「Rails全体でやったら修正量がすごいことになって読みにくそう」「どちらかというとトリビアな部類で、パフォーマンスの改善としてはやや微妙かなー」「レビュアーがString#freezeをいったん勧めてから『ごめん、式展開ではできないんだった』って取り消してる」「確かにここで#freezeはできない」「# frozen_string_literal: trueで十分だったのか」

バグ: raw_write_attributeで主キーにidがマップされていたのを修正

無言で一発mergeされています。

# activerecord/lib/active_record/attribute_methods/write.rb
-        write_attribute_with_type_cast(name, value, true)
+        name = self.class.primary_key if name == "id".freeze && self.class.primary_key
+        @attributes.write_from_user(name, value)
+        value
       end

        def raw_write_attribute(attr_name, value) # :nodoc:
-        write_attribute_with_type_cast(attr_name, value, false)
+        name = attr_name.to_s
+        @attributes.write_cast_value(name, value)
+        value
       end

つっつきボイス:update_columnsでprimary keyの値を設定していると当該オブジェクトじゃなくても更新できてしまったらしい」「privateの#write_attribute_with_type_castが削除されてる」「それはたぶんリファクタリングですね」「ロジックを共有する必要がなくなったからって書いてある」

yumaさんが無言でActiveRecord の attribute 更新方法まとめを参考用にSlackに貼ってくれました。助かります。

Railsガイド: Module#delegate_missing_to

これはもう、まんまドキュメントの追加です。

delegate_missing_to
たとえばUserオブジェクトのmissingを残らずProfileオブジェクトに委譲したいことがあります。
delegate_missing_toマクロで以下のように簡単に実装できます。

class User < ApplicationRecord
  has_one :profile

  delegate_missing_to :profile
end

オブジェクト内で呼び出せるあらゆるもの(インスタンス変数、定数など)が対象になります。
対象のpublicなメソッドのみが委譲されます。
注: 定義場所はactive_support/core_ext/module/delegation.rbです

シンガポールでRedDotRubyConf 2017が開催

昨日6/22(木)と本日6/23(金)開催されました。


www.reddotrubyconf.comより

台湾在住のst0012さんとのチャットで知ったのですが、RedDotRubyConfはビジネス的要素とコアな技術トークの両方の要素を含んでいて、非常にバラエティに富んでいるそうです。スケジュールを見ると女性プレゼンターも目立ちますね。

つっつきボイス: 「まさに今日と明日やってるのか」「matsudaさんもいる」「お、Hanamiも発表してる」「ここでもmatzのキーノートで始まりAaron Pattersonが締めくくってる」「2人とも忙しそう」

Passenger 5.1.5リリース: セキュリティ修正と内部強化などが多数

元記事: Passenger 5.1.5: security robustness fix, internal improvements


blog.phusion.nlより

ダウンタイムの最小化、セキュリティの強化や効率向上など、かなり多数の改善が行われたとのことです。詳しくは今年1月のマイルストーン記事「Passenger 5.1: a new milestone in robustness, security and efficiency」をどうぞ。有料版を購入すればソースにもアクセスできます。

Passengerのつっつきも非常に盛り上がりました。

つっつきボイス: 「Passengerは以前に比べてすごくよくなってる: 特にインストールがとても楽」「嫌いじゃない」「むしろ好き」「ビジネスとしてやってるだけのことはある」「version 2の頃だったかな、有料化して一気にユーザーが離れたのは」「その頃はワーカーがすごくメモリを食ってて、数百回動くと死ぬように作られてたり、それが軽くトラウマだったりはしたけど」「そういえば以前のPassengerは複数バージョンのRubyが共存できない仕様だった」「それ、今は対応済みです」


ワーカーが数百回動くと自ら死んでたとか、昆虫の一生か何かかと思ってしまいました。そういえばworkerってそちら方面の用語では「働きバチ」とか「働きアリ」を指すのでした。


「ja.wikipedia.org/wiki/アリ」より

Hackerone: オープンソースのためのセキュリティ情報


www.hackerone.comより

この間ウォッチでご紹介したAaron Pattersonインタビューで知りました。Railsのセキュリティチームのメンバーも在籍していて、チームの重要なセキュリティ情報源となっているようです。私も登録しました。

つっつきボイス: 「日本のIPAセキュリティ情報に相当することをやってるのか」「中の人が顔出ししてる」

追記

Hackeroneは賞金システムになっており、脆弱性の報告が受理されると、ソフトウェアの種類に応じて賞金が出ます。Ruby on Railsは賞金額2位で1,500ドルとなっています。

動画: SinatraとGoogleスプレッドシートでランディングページを構築(RubyFlowより)

5分程度なのであっという間です。データベースの代わりにGoogleスプレッドシートでLPを作ってみたい方向け。

render_async: Railsページの表示が遅い部分をAjaxで遅延読み込み(Ruby Weeklyより)

# ビューヘルパーでrender_asyncをinclude
# app/views/comments/show.html.erb
<%= render_async comment_stats_path %>

# ルーティングを設定
# config/routes.rb
get :comment_stats, :controller => :comments

# コントローラにロジックを書く
# app/controllers/comments_controller.rb
def comment_stats
  @stats = Comment.get_stats

  render :partial => "comment_stats"
end

# レンダリング用パーシャルを作成
# app/views/comments/_comment_stats.html.erb

<div class="col-md-6">
  <%= @stats %>
</div>

つっつきボイス: 「これ、結構いいかも!」「めちゃ重いサイトを遅延読み込みするヘルパーということか」「同じようなもの書いたことある」「コアもシンプル↓」「サーバーサイドレンダリング(SSR)問題についてはさすがに未対応かなー」「render_asyncというネーミングってどうでしょう?」「うん、内容にも合ってるしいいと思う」

# https://github.com/renderedtext/render_async/tree/master/lib/render_async
require 'securerandom'

module RenderAsync
  module ViewHelper
    def render_async(path)
      container_name = "render_async_#{SecureRandom.hex(5)}#{Time.now.to_i}"
      render "render_async/render_async", :container_name => container_name,
                                          :path => path
    end
  end
end

日本のRuby事情(Ruby Weeklyより)


appfolio-engineering.squarespace.comより

先週Twitterで見かけたのですがウォッチに載せそこなってました。
日本のRuby事情、特にコミュニティ関連事情を詳しくレポートしています。ちら見しただけですが、米国はRailsあってのRubyという感じなのが日本だとRubyそのものが根強いとか、日本発の言語ということで政府のバックアップがある点などについて触れ、Ruby World ConferenceやRubyKaigiにも言及して、「Rubyの使われ方が米国とはぜんぜん違うなー」という感じで締めくくっています。

つっつきボイス: 「海外から見た日本のコミュニティ事情面白そう」「日本はいろいろ独特なんだな」「翻訳があったら読みたいなー(チラッチラッ」「読みたいー」

RubyオブジェクトをActive Modelでバリデーション(Ruby Weeklyより)

上の「動画: SinatraとGoogleスプレッドシートでランディングページを構築」の続きという感じです。SinatraでがんばってActive Modelバリデーションしています。

つっつきボイス:ActiveModel::Validationsは確かにWebアプリ以外でも便利そう」

Rubyのキューを深掘り(Ruby Weeklyより)

半分以上はC言語です。末尾では、ワーカーを終了させつつ、popでブロックされてたらワーカーを起動するという動作を「poisonオブジェクト」を使って実現する方法も紹介されています。

# https://schneems.com/2017/06/14/meditations-on-writing-a-queue/ より
require 'thread'

GLOBAL_QUEUE = Queue.new
POISON       = Object.new

threads = 10.times.map do
  Thread.new do
    loop do
      work = GLOBAL_QUEUE.pop
      break if work == POISON
      puts "Working on #{work}"
    end
  end
end

20.times do |i|
  GLOBAL_QUEUE.push(i)
end

10.times do
  GLOBAL_QUEUE.push(POISON)
end

threads.map {|t| t.join }

つっつきボイス: 「キューはキューでもblocking queueの実装の話か」「キューはいろんなところで使われるから読んでおくといいかも」

Dox gemでRSpecからAPIドキュメントを自動生成(Ruby Weeklyより)

markdown形式で生成できるそうです。デモサイトがいくつかあるのでそちらを見るのが早いと思います。


infinum.github.io/dox-demo/snowboardより

つっつきボイス: 「なかなか表示がリッチでいい感じ」「APIサーバーだけ開発するとき、これも使うとドキュメント作りに便利そう」「その場でSpecを実行できるのか」「ソースも見られる」「以前これと似たようなgemを社内で使おうとした人がいてそちらは全然使い物にならなかったらしいんだけど、なんて名前だったかな」

ブライトンRuby Conference 2017(Ruby Weeklyより)


brightonruby.comより

イギリスでもRuby Conferenceが開かれるんですね。開催は来々週の7月7日です。

つっつきボイス: 「お、クックパッドがGoldスポンサーになってる」

シンボルマークのモスクみたいなのは何だろうと思ったら、ロイヤル・パビリオンのようです。名古屋の金のしゃちほこみたいな定番イメージなんでしょうね。

mixinを避けた方がよい理由(Ruby Weeklyより)

この記事もこの間から見かけていたのですが、ウォッチに載せそびれていました。「mixinは継承を別の文法にしたようなものだ」「継承もだいたいそうだが、特にmixinはコンポジションにしよう」だそうです。

つっつきボイス: 「以前のウォッチでもmixin順序と継承でカオス化する記事を読んだ気がする」「モジュールが増えたときが問題か」

翌日のチェックでもつっついていただいたので追加します。

つっつきボイス2:「mixinだから悪い、モジュール使ってるから悪い、とは思えない」「多重継承は確かにわかりにくいし問題を起こしやすいけど、Rubyの継承の順序はわかりやすい方だと思う」「モジュールがいろんなファイルに分かれていて読みにくいというのは、エディタのタグジャンプとかを使いこなせれば大きな問題にはならないかも」「たぶん重要なのは差分プログラミングを正しく行うことの方なんじゃないかなー」「Railsだったらconcerningを上手に使うとか」「そのためには目の前のコードだけじゃなくて、継承関係も意識するとよいかも(メソッドで言うと#ancestors)」「z軸というか3次元的に継承の奥行きを捉える視点を持つ感じかな」

Ruby Laser: もうひとつのrubygems.org(Awesome Rubyより)


rubylaser.orgより

まだgemの数は少ないですが、検索が速いですね。個人的にはRuby Laserという名前が気に入っています。私の年代だとレーザー光線源にはたいていルビーが使われてたというだけです。今ではシミ取りぐらいにしか使われてないそうですが。

情報源のAwesome Rubyがなかなか優秀なので、ここも今後巡回します。


そこからこの種の情報サイトの浮き沈みについて話題になりました。

つっつきボイス: 「こういう情報サイトってぱっと消えちゃうこと多いよね」「RubyInsideは4年前からまったく更新されてないのにTwitterアカウントだけすごく元気」「それbotじゃなくて?w」

Ruby Toolboxの今後について(Ruby Weeklyより)


www.ruby-toolbox.comより

先週Ruby Toolboxサイトがクラッシュしたのを機に、これまでクローズドだったサイトをオープンソースにしようかどうしようかと問いかけています。

つっつきボイス: 「面白そう、後で読もっと」

Railsのform_withform_forform_tagと比較(Ruby Weeklyより)

form_forの場合:

<!-- m.patrikonrails.com より -->
<%= form_for @user do |form| %>
  <%= form.text_field :email %>
  <%= check_box_tag :send_welcome_email %>
<% end %>

form_withの場合:

<!-- m.patrikonrails.com より -->
<%= form_with model: @user, local: true do |form| %>
  <%= form.text_field :email %>
  <%= form.check_box :send_welcome_email %>
  <%= form.submit %>
<% end %>

今後はform_withにしよう!振り返るな!

つっつきボイス: 「まform_forform_tagはdeprecatedだしw」「form_withではmodel:を書くべしという感じになってきた」

受け入れテストをアクター/ペルソナで書く(Ruby Weeklyより)


blog.arkency.comより

つっつきボイス: 「これもよさそう: 後で読もう」「↑この取り合わせになってしまうことってよくあるけど、本当にちゃんとテストできているんだろうかという気持ちになることが多い」「どこか無理矢理感ある」

使えるgemを見極める7つのコツ(Ruby Weeklyより)


www.saturnflyer.comより

  • リポジトリの★とwatchの数
  • アクティブなissueとプルリクの数
  • 前回のリリース時期
  • 依存関係の数
  • メンテナーが怖くないこと
  • 変更がmergeされてないforkの数
  • ドキュメントがあるかどうか

オチは8つめの「そのコードを自分が読んで理解できるかどうか」でした。

つっつきボイス: 「全部同意できる!」「8つ目、別にcrazyじゃないなー」「定番といえばそれまでだけど、まとめ方がうまい」「怖いメンテナーいるいる: 日本人なのに英語で書かないと許さんとか」「怖い人集まってるとこ、あるある」「普通にしてても怖く見えるだけなのかなー、単に顔が怖い人みたいに」「いやいや、もうそういう怖い人たちにとっては怒るのが普通なんですよw」

lemme-pry: pry利用中に依存gemを自動読み込み(Ruby Weeklyより)

珍しくGitLabサイトに置かれているせいか、まだ★がありません。

$ gem install lemme-pry
$ lemme-pry activesupport
...crunching gems...
Using activesupport 5.1.1 (was 4.2.6)
...
[2] pry(main)> 1.second
=> 1 second

パイプも使えるそうです。

$ echo 'time = Time.now' | lemme-pry
...initing stuff...
[2] pry(main)> time
2017-05-25 18:23:40 +0200

バージョン指定とかやりたい場合はGemfile書いてbundlerでやる方がいいかも、だそうです。

つっつきボイス: 「(その場で動かして)うん、動いた」「gemがなくても取ってきてくれるのか」「このgemってどこに入るの?」「やっぱりシステム側に入るみたい」「Gemfileもケアしてくれるといいのに」

Corneal: SinatraでもRailsみたいにgenerateしたい方に(Ruby Weeklyより)


thebrianemory.github.io/cornealより

corneal new APP-NAMEとかcorneal scaffold NAMEとかcorneal model NAMEとかできるそうです。起動はshotgunです。

Sinatraといえばフランク・シナトラなので、Cornealもそういう昔の歌手をもじったのかなと思いましたが違うようです。

つっつきボイス: 「↑この絵がいい」「素直にRails使えばいいんじゃね?」

Rollout: Redisベースでサービスの機能を制御するスイッチ(Ruby Weeklyより)


github.com/fetlife/rollout/issues/113より

つっついたときは一同あまりピンと来なかったのでさっと流してしまいました。rollout_dashboardなどと組み合わせてサービスの機能をオン・オフ・調整したりするgemのようです。★は2,200を超えています。

Insights: SQL不要の分析ツール(Ruby Weeklyより)


github.com/mariusandra/insightsより

デモサイトを見るのが早いですね。

SequelCombine: データセットの結合(PostgreSQL限定)(Ruby Weeklyより)

DB[:groups].columns
  #=> [:id, :name]
DB[:users].columns
  #=> [:id, :username, :email, :group_id]
DB[:groups].combine(many: { users: [DB[:users], id: :group_id] }).to_a
  #=> [{:id=>1,
  #     :name=>"Football",
  #     :users=>
  #       [{
  #           :id=> 1,
  #           :username=> "leonardo",
  #           :email=> "leonardo@fakemail.com",
  #           :group_id=> 1,
  #         },
  #         {
  #           :id=> 2,
  #           :username=> "leonardo2",
  #           :email=> "leonardo2@fakemail.com",
  #           :group_id=> 1,
  #         },
  #       ]
  #   }]

つっつきボイス: 「JSONみたいなものの組み立てがやりやすくなるのかな?」「READMEのとおりにやってみたけどうまく動かない…」「こういう感じのものならFacebookが開発したGraphQLの方がよさそうに見える」

ダウンタイムなしでデータベースの巨大なテーブルにインデックスを付ける(RubyFlowより)

短いのですぐ読めます。

def change
  add_index :builds, :build_metric_id, :algorithm => :concurrently
end


semaphoreci.comより

つっつきボイス: 「要するにPostgreSQLの機能使ってるのか」「PostgreSQLなら驚かない」「最近のPostgreSQLすごいから」「昔MySQLでテーブル複製してインデックスつけてから差し替えたりとか苦労したのを思い出した」

Aquatone: ドメイン名調査ツール(GitHub Trendingより)

Rubyで書かれたネットワークツールで、Node.jsも使っているようです。

aquatone-discover --domain example.com --sleep 5 --jitter 30

aquatone-scan --domain example.com

つっつきボイス:digコマンドで足りるんじゃないかな?」「それ系の機能をひととおりぶちこんだ感じ」

Liquid: Shopify作のWebテンプレート言語(GitHub Trendingより)

Webテンプレート処理用gemです。Shopifyは大手通販サイトですね。

<ul id="products">
  {% for product in products %}
    <li>
      <h2>{{ product.name }}</h2>
      Only {{ product.price | price }}

      {{ product.description | prettyprint | paragraph }}
    </li>
  {% endfor %}
</ul>

つっつきボイス: 「これJekyllで使われてるやつだ、ちょうどこの間Jekyll使ったから」

Catphish: フィッシングに使える空きドメイン名をリストアップ(GitHub Trendingより)


github.com/ring0lab/catphishより

悪用厳禁なやつです。マイナーな言語の紛らわしい文字をどんどん追加しているようです。

つっつきボイス: 「面白ーいw」「これ好き」「つかgemですらないのか: catphish.rbが本体」「ac.jpとかeduドメインは普通なかなか詐称できないけど、.によく似た文字があれば国立大学ドメインっぽいのも取れるなw」「fileformat.infoあたりで探せば見つかるかも」「このPunycodeがあるドメインって、Slackに貼ったときに切り替わって邪魔なんだよなー」「そのせいでSlackに貼れないドメインがあった」

番外: Bootsnap gemがRailsにデフォルトで追加される?

y-yagiさんのブログで知りました。先週の翻訳記事「RailsConf 2017のパフォーマンス関連の話題(1)BootsnapやPumaなど」でも取り上げられていた起動高速化gemのBootsnapがもしかするとRailsに加わるかもしれません。

そういえばこのBootsnapもShopifyのgemでした。

つっつきボイス: 「この手の副作用の少なそうな高速化の仕組みは取り入れられやすいかも」「spring gemを追加したときの意図に似ているかな」「tumblrってブログ書けるんですか?」「え?」「え?」


今週は以上です。

関連記事

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

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

Rails公式ニュース

Ruby Weekly

Awesome Ruby

OpenRuby

RubyFlow

160928_1638_XvIP4h

Github Trending

160928_1701_Q9dJIU

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を運営。 実は最近Go言語が好き。 仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

週刊Railsウォッチ

インフラ

BigBinary記事より

ActiveSupport探訪シリーズ