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

週刊Railsウォッチ(20170707)Railsの新機能ActiveStorage、高速Rubyフォーマッタrufo gemが超便利、Railscasts全コンテンツが無料公開ほか

こんにちは、hachi8833です。そういえば今日は七夕でした。

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

臨時ニュース: Railsの新機能「ActiveStorage」

つい先ほど知りました。まだ詳しく見ていませんが、AWSのS3やGoogle Cloud Storageなどのクラウドを透過的に扱えるようです。DHHのfirst commitもわずか19時間前というスピード公開です。

class User < ApplicationRecord
  has_one_attached :avatar
end

user.avatar.attach io: File.open("~/face.jpg"), filename: "avatar.jpg", content_type: "image/jpg"
user.avatar.exist? # => true

user.avatar.purge
user.avatar.exist? # => false

user.avatar.url(expires_in: 5.minutes) # => /rails/blobs/<encoded-key>

class AvatarsController < ApplicationController
  def update
    Current.user.avatar.attach(params.require(:avatar))
    redirect_to Current.user
  end
end

⭐⭐Rufo: Rubyの高速なフォーマッタ(Ruby Weeklyより)⭐⭐

  • リポジトリ: ruby-formatter/rufo(追記: /asterite/rufoからリポジトリが移動していました)

rubocopの手の届かないようなかゆいところの書式を瞬時に修正してくれます。公開後1月も経たないうちに★200個超えです。

パーサーとしてRuby純正のRipperを使っているという行儀のよさもうれしい点です。

デフォルトの修正は極力控えめかつエラー時以外は何もメッセージを出さないので、必要に応じて.rufoを追加して指定を追加するというアプローチです。.rufoがない場合は、ダブルスペースなど本当にミニマムな部分しか修正しません。.rufoをリポジトリに登録すれば、gem install rufoするだけで設定を共有できます。

class Foo
  include Bar
  extend  Baz   # 例: デフォルトでは縦揃え用のスペースは維持する
end

つっつきボイス: 「おお、これ( ・∀・)イイ!!」「RubyMineの書式修正は強力なんだけど、非RubyMineの人と共同作業するときに書式合わせるのがつらいなって思ってたところだった」

#A
foo.bar
   .baz

#B
foo.bar
  .baz

「↑自分はBにしたい派」

「これ、欲しかったって言ってたやつでしょー、ほれほれ」「Vim/Emacs/Sublime/VScodeとかのプラグインはあるけどRubyMineのがないや」「Filewatcher使えばRubyMineでも使えると思う」

さっそくRubyMineでやってみました↓。ついでにSublime Text 3にもsublime-rufoを仕込みました。どちらもファイルを保存した瞬間にダブルスペースなどを退治してくれるようになったので大変快適です。RubyMine用プラグインはよ。

今週の⭐をダブルで進呈いたします。おめでとうございます。

Rails: 今週の改修

今週は公式サイトの更新がまだないので、commitログからピックアップしました。

改良: 同じエンジンを場所を変えてマウントできるようになった

# https://github.com/rails/rails/pull/29662/files#diff-2c5abce90a3e5c448e74cf9128a6cff6R1357
+      app_file "config/routes.rb", <<-RUBY
+        Rails.application.routes.draw do
+          scope "/fruits" do
+            mount Bukkits::Engine => "/bukkits", as: :fruit_bukkits
+          end
+
+          scope "/vegetables" do
+            mount Bukkits::Engine => "/bukkits", as: :vegetable_bukkits
+          end

つっつきボイス: 「これはもうそのまんまですな」

prefix: trueのときにModule.delegate*付けて返すよう修正

prefix: trueprefix: :anythingを指定するとActiveSupportの#delegateが期待どおりに動かなかった問題が修正されました。

class MyClass
  private *delegate(:this, :that, :another, to: :some_method)
end

eachmapに変更しただけというピンポイント修正です。

# https://github.com/rails/rails/pull/29687/files#diff-01f2db2585c06eca03cf014cfe51c50eL177
-    methods.each do |method|
+    methods.map do |method|

つっつきボイス: 「splat演算子*か」「そういえばsplat演算子はあまり使ってない」


さらに、merge後にkamipoさんがそっとテストを修正してくれていました。interpreted as argument prefix warningの修正です。

# https://github.com/rails/rails/commit/6bb115a6617b320b8ff13a4561ddf8d1a9b44f82#diff-7963aa045919b7dde7288811b1608eedL402
-      private *delegate(:street, :city, to: :@place)
+      private(*delegate(:street, :city, to: :@place))

ActiveModel::Type::DateTime#serializeがシリアライズ時にDateTimeではなくTimeを返すよう修正

ActiveModel::Type::DateTime#serializeActiveModel::Type::Date#serializeの挙動を揃えました。

# https://github.com/rails/rails/pull/29676/files#diff-c7552cfb0260bcf669421ff13d657b39R13
+      def serialize(value)
+        super(cast(value))
+      end

Ruby trunkより

bit_lengthの負の整数での挙動

超超ざっくりなやりとり:

Q: これって負の補数表現としておかしくない?

(-1).bit_length => 0
(-2).bit_length => 1
(-3).bit_length => 2
(-4).bit_length => 2

# 2の補数で表した負の整数↓
-1 =>  111111111111111111
-2 =>  111111111111111110
-3 =>  111111111111111101
-4 =>  111111111111111100

A: いや、正しい。RubyのIntegerは理論的に桁数無限なんだし、2の補数で考える方がおかしい。

Q: ごめん、公式ドキュメントにちゃんと書いてあったわ。

bit_length → integer
intの値のビットの数を返す。
ここでいう「ビットの数」はそのビットの最上位のビット位置のことであり、符号ビットは含めない(2**nのビット位置はn+1になる)。該当するビットがない(ゼロや-1)の場合はゼロを返す。


つっつきボイス: 「へええ、bit_lengthってそういう挙動なんだ」「符号抜きで、その数値を表すのに必要なビット数を返すということか」「うん、確かに-1と0では0が返る↓」「どんなときに使うんだろう?」「関係ないけど、complement(補完)ってcompliment(賞賛)とスペルがすごく似てて紛らわしいです」

[12] pry(main)> -1.bit_length
=> 0
[13] pry(main)> 0.bit_length
=> 0
[14] pry(main)> 1.bit_length
=> 1

バグ: Marshal#dumpしたTime#zoneを読み込んで+/-するとnilが返る

a = Marshal.dump(Time.now)
b = Marshal.load(a)
p b.zone  # CST
p (b + 1).zone # nil
p (b - 1).zone # nil
p (Time.now + 1).zone # CST

つっつきボイス: 「えー、これ結構いやなバグだ」「Marshalにこんなのあったら困るわー」「+ 1は秒なんですね?」「そうそう」

RailsCastsの全コンテンツが無料公開に(Ruby Weeklyより)


railscasts.comより

2013年に燃え尽き症候群になってしまったRyan Batesさんが少しずつ活動を再開しているようです。

2017/06/27
最後のRailsCastsエピソードを制作してからもう4年の月日が経ちました。今こそ従来の有料コンテンツを無料公開するときだと思いました。Pro版と更新版エピソードはすべて無料でご覧いただけます。
応援してくださった皆さまには深く感謝いたします。皆さまのおかげで私の人生は大きく変わりました。素晴らしいRailsコミュニティの一員であることを嬉しく思います。コミュニティの皆さまから大変多くの応援や励ましをいただきました。批判ですら建設的かつ前向きなものでした。
私にとって教えることは情熱です。しかしながらフルタイムでのRailsCasts活動にシフトしたことで、私は燃え尽きてしまいました。実際に開発したものでないアプリを元に教材を制作することは困難であり、実際のアプリに役立つアイデアが盛り込まれているかを念入りに確かめながらのシナリオ制作は消耗が激しく、時間がかかるようになってきました。
いつの日かRailsCastsに復帰または何らかの講師になることがあるかもしれませんが、これまでの休業期間中にどうにかreinteractiveの仕事でRails開発に復帰しはじめたところです。これをきっかけにコミュニティに復帰する日を待ち望んでいます。またコミュニティでお会いしましょう。

--Ryan


つっつきボイス: 「おー」「Railscasts有料のままでもいいから活動再開して欲しい」「無料になったコンテンツもやっぱり2013年までのばかりですね」

そこからRailscastsの功績の大きさについて話題になりました。


つっつきボイス: 「Railscastsは本当にいい技術情報サイトだった: お金払って見てたし、その価値があった」

「Railsのライブコーディングの元祖と言ってもいい: 今でこそ隆盛を極めているけど」「15分でアプリ作るとかそういうやつですね」

「RubyMineやいろんなエディタでカラースキームの名前として使われるほど時代を築いていたのに」「そういえば自分もRubyMineとSublimeのカラースキームはRailscastsにしてる」

「ぼく見たことないです」「Σ(゚◇゚;)マジデッ!?」「仕事でRails使い始めたのは5からなんでw」

実際ネットでRyan Batesさんを英語で検索すると、突然の活動停止を惜しむ声と復帰を望む声がざくざく出てきます。

1ファイルのRailsアプリ(Ruby Weeklyより)

先週別口で見つけてご紹介しようと思ってたのですが貼り忘れてました。最終的な1ファイルRailsはgistで見られますが、ポイントはとにかくbundlerをいかに組み込むかだったようです↓。

# https://gist.github.com/clupprich/0e8b816883ca4dac6b7632a9e8351c48より
begin
  require "bundler/inline"
rescue LoadError => e
  $stderr.puts "Bundler version 1.10 or later is required. Please update your Bundler"
  raise e
end

gemfile(true) do
  source "https://rubygems.org"

  gem "rails"
  gem "pg"
  gem "factory_girl_rails"
end

...

つっつきボイス: 「ああなるほどーw」「確かにbundlerが問題だよな」「ファイルひとつのRailsアプリだと楽に配布できそう: パーミッションとか気にしなくていいし」「さすがにgemそのものまでは組み込めないか」「もし組み込んだらすごいサイズになるw」

bundlerが早くRuby標準の組み込みライブラリになればいいのにと思います。

追伸: 元記事の続編が公開されました。

Screencast: Rails 5.1でMySQLのVirtualカラムを使う(RubyFlowより)

5分程度なのですぐ終わります。


つっつきボイス: 「MySQLのVirtualカラムって何?っと思ったらこれか」「生成カラム、つまりいわゆるcomputedなカラムにVirtual(実データを保持しない)とStored(実データを保持する)の2種類があるのか」「PostgreSQLには前からあるな」

Konacha: RailsのJSテスティングgem(RubyFlowより)


blog.botreetechnologies.comより

Konachaはmocha.jschai.jsを使っています。★は1000個を超えてます。JavaScriptとCoffeeScriptのどちらでもテストを書けるようです。

// https://github.com/jfirebaugh/konacha より
//= require array_sum

describe("Array#sum", function() {
  it("returns 0 when the Array is empty", function() {
    [].sum().should.equal(0);
  });

  it("returns the sum of numeric elements", function() {
    [1,2,3].sum().should.equal(6);
  });
});

同記事では類似のgemとして以下もリストアップされていて、Konachaも含めてなぜか皆お茶がらみの命名です。

類似gemには他にevergreenもあります。緑ということで無理やりお茶がらみと思ってもよいのかしら。


つっつきボイス: 「mocha.jsは聞いたことあるけどchai.jsって初めて聞いたw」「Jasmineは有名」「Konachaの方が★が多いのか」「teaspoonはPhantomJSにSelenium WebDriverかCapybara Webkitを使ってる」

2017年: Rubyに代わる言語は?(RubyFlowより)

1つのランキングに頼らずいろんなランキングを比較しているのがちょっとよさそうです。


つっつきボイス: 「こればっかりはねー」「先のことはわがんね」「個人的に来そうなのはElixirとKotlinあたりかな」

RedDot Ruby Conf 2017の動画

6月にシンガポールで開催されたRedDotRubyConf 2017ウォッチでもお伝えしましたが、動画がひととおり出揃ったようです。


つっつきボイス: 「おおー、スライドのサムネイルの色遣い」「日本人とはだいぶ色彩感覚違うなー」「アメリカ人ともまた違う感じ」

三部作: RailsでGraphQL APIを作る


gist.github.com/wayne5540より


つっつきボイス: 「これなかなかいいかも」「Part 1はともかくPart 2と 3はよさげ」「とりあえず図はとてもわかりやすかった」「graphql-rubyがGraphQLのサーバーサイドのgemか」

# github.com/rmosolgo/graphql-ruby より
# app/graph/types/query_type.rb
QueryType = GraphQL::ObjectType.define do
  name "Query"
  description "The query root of this schema"

  field :viewer do
    type UserType
    description "Current user"
    resolve ->(obj, args, ctx) {
      ctx[:current_user]
    }
  end
end

つっつきボイス: 「サーバー側ではこんな感じに書くのか」「GraphQLのクエリはJSONだから誰も異論はないと思うけど、サーバー側のコードの書き方はまだ議論が出そうな気がする」

Lock-freeキューの書き方(Ruby Weeklyより)


www.schneems.comより

C言語を交えつつconcurrent-rubyを使ってRubyでLock-freeしています。

関係ありませんが、smoking-free(禁煙)を「喫煙自由」と勘違いした笑い話を思い出しました。freeは前から形容するか後ろから形容するかで大きく意味が変わります。


つっつきボイス: 「こういうのをやるときにはむしろC言語の方がシンプルかもしれない」「Lock-freeキューはコンピュータサイエンスの授業に出てきそう」「Wait-freeというアルゴリズムもあるのか」

ついにTensorflow.rbが登場(RubyFlowより)

機械学習では定番のPythonライブラリ「Tensorflow」のRuby版です。
あと少しで★500です。ちょうどGitHub TrendingでもAwesome Machine Learning with Rubyというまとめリストがあがってました。


つっつきボイス: 「TensorflowそのものはGoogleが出してますね」「このTensorflow.rbは直接のかかわりはないのかな」「Google公式ならもう少し安心感ありそうなんだけど」


全然関係ありませんが、私の年だとつい「もっとひっぱる いわくテンソル」という歌を思い出してしまいます。

Tenser, said the Tensor.
Tenser, said the Tensor.
Tension, apprehension,
And dissension have begun.
https://en.wikipedia.org/wiki/The_Demolished_Man#Plotより

RubyとParsletとElasticsearchでクエリパーサーを書く(Ruby Weeklyより)

有限状態機械なども登場する本格的な内容です。

# http://www.recursion.org/query-parser/ より
class QueryParser < Parslet::Parser
  rule(:term) { match('[^\s]').repeat(1).as(:term) }
  rule(:operator) { (str('+') | str('-')).as(:operator) }
  rule(:clause) { (operator.maybe >> term).as(:clause) }
  rule(:space) { match('\s').repeat(1) }
  rule(:query) { (clause >> space.maybe).repeat.as(:query) }
  root(:query)
end

つっつきボイス: 「おお、いかにもコンピューターサイエンス」「大学でやってたんでしょそういえば?」「やってましたが、後になるほどCPUの種類ごとにこまごまと作業しないといけなかったのがつらかったです」

PostgreSQLでUnicodeと遊ぶ

PostgreSQLのエキスパートDimitri Fontaine氏の記事です。

  select count(*) as victories,
         forename, surname,
         flag(country.code)
    from drivers
         left join results
                on drivers.driverid = results.driverid
               and results.position = 1
         join nationalities using(nationality)
         join country
           on country.name = nationalities.country
group by drivers.driverid, country.code
order by victories desc
   limit 10;


tapoueh.orgより


つっつきボイス:寿司ビール問題がないからのびのびやってますねw」「MySQL(,,゚Д゚) ガンガレ!」

Re:VIEW -- ドキュメントフォーマッタ/コンバータgem


/reviewml.org/jaより

ふと目に止まったので取り上げてみました。Re:VIEWは日本語版のRailsチュートリアルRailsガイドの電子書籍化作業でも使われています。


つっつきボイス: 「Re:VIEWってググりにくい」「傍で見ててもパブリッシングは本当大変です」

GitLab 9.3でグループの階層化をMySQLではサポートしないことに

morimorihogeさんがBPSのSlackに投下した記事から。パフォーマンス上の理由だそうです。


つっつきボイス: 「subgroupってなんだろ」「groupの下にgroupが作れるっぽい?です↓」「namespaceの下に階層が切れるのか」


docs.gitlab.comより

Flatware: テストを並列処理して時間を短縮するgem

ZeroMQという並列処理フレームワークを使っており、RSpec/miniTestを問わず使えるそうです。★はまだ41個。


つっつきボイス: 「こういうのいろいろあるからなー」「これじゃなくてもいい気がする」

ペアプログラミングQ&A


hashrocket.comより

hashrocket.comはペアプログラミングに力を入れているらしく、他にも記事があります。「最初は時間はかかるが、それに見合った効果は必ずある」という趣旨です。


つっつきボイス: 「これもなかなかいい記事」「社内でもペアプロを開催してみたい」「最近だとモブプロも話題らしい」「モブプロ?」「モブって「群衆」のmobですね」「1人が書いて他が後ろで思い思いにツッコむみたいな」「気の弱い人だと泣いちゃったりとか?」「書く人は書くことにだけ集中するものらしい」

FasterPath: Rubyのファイル読み込みを高速化するgem(Awesome Rubyより)


github.com/danielpclark/faster_pathより

コア部分はRustで書かれているそうです。bootsnapなどと同様、インストールするだけで効くgemのようです。

$ gem install faster_path

つっつきボイス: 「おお、これもよさそう」「パスの読み込みはスキャンが発生するからパフォーマンスへの影響大きい」「いずれRuby本家に取り込まれてもおかしくない感じ」

Ahoy: Railsのイベントをトラック(GitHub Trendingより)

イベントをトラックして、FluentdやRabbitMQなどのさまざまなデータストアに保存できます。あと少しで★2,000です。


github.com/ankane/ahoyより

$ gem 'ahoy_matey'

つっつきボイス: 「アホい?w待てい?w」「イベント出力とかトラッキングとかいろいろやりたいときに便利そう」

チェコ語、スロヴァキア語、スロヴェニア語などのアホイ ahoj は、出会いの挨拶である。英語の hi にあたるくだけた表現である。
英語の ahoy・ドイツ語の ahoi は、海上で他の船に呼びかけるときの挨拶である。
Wikipedia-ja アホイより

小松左京の小説「復活の日」で、アホイという呼びかけをアマチュア無線の救助信号で使ってたのをたった今思い出しました。

Regexp-examples: 正規表現に対応する具体例を生成するgem(Awesome Rubyより)

単なるサンプル集ではなく、正規表現に合わせてサンプルを生成してくれます。個数だって指定できます。

/this|is|awesome/.examples
#=> ['this', 'is', 'awesome']

/(I(N(C(E(P(T(I(O(N)))))))))*/.examples
#=> ["", "INCEPTION", "INCEPTIONINCEPTION"]

/[F-X]/.examples(max_group_results: 10)
 #=> ['F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O']

それすらだるい人にはランダム生成もやってくれます。

/\p{Greek}{80}/.random_example
#=> "ΖΆΧͷᵦμͷηϒϰΟᵝΔ΄θϔζΌψΨεκᴪΓΕπι϶ονϵΓϹᵦΟπᵡήϴϜΦϚϴϑ͵ϴΉϺ͵ϹϰϡᵠϝΤΏΨϹϊϻαώΞΰϰΑͼΈΘͽϙͽξΆΆΡΡΉΓς"

つっつきボイス: 「これも(・∀・)イイ!!」「自分で書いた正規表現で思わぬマッチが起きてないかどうかチェックするのに使えそう」「正規表現厨としては即インストールだ」

Devise vs JWT(Awesome Rubyより)

JWTがDeviseと人気を二分しているのが気になって取り上げました。


つっつきボイス: 「なぬ、JVM?」「あ、入力ミス💦: JWT(JSON Web Token)でした」「びっくりしたー、なんでDeviseがJVMと張り合うのかとおもたw」
JWTを使ってるサービス最近よく見かけるし、APIサービスの認証にはいいかも」「JWTはパスワード認証とかに使うものじゃないけどね: そんな機能ないし」


jwt.ioより

ActiveRecordのafter_commitコールバックを呼ぶタイミング(Ruby Weeklyより)

# medium.com/@gnfisher より
class MyModel
  after_commit :api_call_and_update, on: :create

  ...
  def api_call_and_update
    # API call to move resource from temp to proper S3 bucket...
    self.update(bucket: 'New bucket')
  end
end

つっつきボイス:after_*系のコールバックは何かと地雷を踏みやすい: コールバックで#updateしちゃってる↑とか」「before_*に比べて地雷になりやすい印象」

odyssey: 英文の読みやすさを数値化するgem(Ruby Weeklyより)


blog.redpanthers.coより

小学校五年(5th grade)だと「とても読みやすい」、高校生(10th to 12th grade)だと「だいぶ読みにくい」といった具合に、難しい単語ベースかなにかで文章のスコアを出します。


つっつきボイス: 「これも有能」「英語はこういうスコアリングが日本語よりやりやすいし、ツールも豊富でうらやましいです」

著名なgemから学んだ6つのこと(Ruby Weeklyより)

SidekiqやActiveSupportなどのgemを読む記事です。

# blog.arkency.com より
# Sidekiq::Client initializer
module Sidekiq
  class Client
    def initialize(redis_pool=nil)
      @redis_pool = redis_pool ||
      Thread.current[:sidekiq_via_pool] ||
      Sidekiq.redis_pool
    end
  end
end

つっつきボイス: 「これも面白い」「この間Pumaのコード読んだときにも、この記事に出てくるような謎のidiomあった」「サーバーやフレームワークにはそれにふさわしいコードの書き方があるので、Railsアプリを書くのとはおのずと違ってくる」

RailsのServiceオブジェクト3か条(Ruby Weeklyより)


hackernoon.comより

  1. publicなメソッドはできるだけ1つに絞り込むべし
  2. 依存関係はprivateに持ち込むべし
  3. 戻り値は意味のあるもの(オブジェクト)を返すべし

つっつきボイス: 「Serviceオブジェクトのありかたとして理解できる: よい」「無意味なtrue/falseしか返さないオブジェクトとかホント困る」

インタビュー: Railsでコードを書き始める際の心得

定番リンクや動画などを簡単に紹介している初心者向けの記事です。


つっつきボイス: 「インタビューって、誰に?」「よくわからないけどRailsのインストラクターみたいですw」「社内新卒向けの記事かな」

GraphQL系の記事たち

最近ちょっとGraphQLを調べていて目に止まった記事たちです。

GraphQL-Ruby


graphql-ruby.orgより

RelayとRailsでGraphQL

RailsとGraphQLでAPIサーバーを構築

GraphQL APIで便利なツールや拡張機能

Vue.jsとApolloでGraphQLを使う

Colorls: Rubyで書かれたlsコマンドカラー化(GitHub Trendingより)


github.com/athityakumar/colorlsより

lsコマンドのカラー化とアイコン表示のgemです。


つっつきボイス: 「よーやるw」「nerd-fontが必要なのか」「今使ってるカラー化がPython 3用で、Python 2と喧嘩して困ってたので、これにしようかな」

拡張しやすいコードを書くのではなく、削りやすいコードを書け

  1. コードをそもそも書かない
  2. コードをコピペで済ます
  3. コピペをしない
  4. ボイラープレートを書く
  5. ボイラープレートを書かない
  6. 巨大なコードを書く
  7. コードを細かく分割する
  8. とにかくコードを書く

つっつきボイス: 「いい記事」「構成がうまい!」「このうまい言い回し、元ネタがあるのかな?」

GoogleスプレッドシートでVMつくったお(HackerNewsより)


briansteffens.github.ioより

HackerNewsで2位にあがっていました。


つっつきボイス: 「これすごい!ヽ〔゚Д゚〕丿 ハイスゴイスゴイ」「レジスタとかメモリとか見やすいし」「授業でCPUの仕組みを扱うときなんかに便利そう」


今週は以上です。

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

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

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

Rails公式ニュース

Ruby Weekly

Awesome Ruby

RubyFlow

160928_1638_XvIP4h

Hacker News

160928_1654_q6srdR

Github Trending

160928_1701_Q9dJIU


CONTACT

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