- 開発
週刊Railsウォッチ(20170818)RailsとYarnでTypeScript、Rails新コミッタにkamipoさんも、CSVにSQLクエリをかけられるツールほか
こんにちは、hachi8833です。octotreeといういいものがあるのを知らずにGitHubで毎回真正面からディレクトリ掘ってました。
お盆明けのRailsウォッチ、今週は軽めの構成です。それではいってみましょう。
Rails: 🎉🎉 新committerが3名: kamipoさんも(Rails公式ニュースより)🎉 🎉
committer入りした3名様、お疲れさまです&おめでとうございます!
- George Claghorn: Active Storageほか
- Javan Makhmali: JavaScript周り、特にWebpacker
- Ryuta Kamizono: ActiveRecordほか
Ryuta Kamizono: Ryuta is a top 20 all-time Rails contributor with work going back to 2013. He's got his fingerprints all over the framework, but have in particular been helping with Active Record. Ryuta lives in Tokyo.
つっつきボイス: 「Ryutaだと一瞬だけピンとこないですね」「2013年からトップ20って、凄!」「DHHが手放しで褒めちぎってるw」「fingerprintsは技術用語かつ比喩ですね」「PostgreSQL周りといえばkamipoさんという印象」
「contributorとcommitterの違いって気にしてなかったけど、contributor→committerなのか」
「いつもの話ではあるけど、こうやって陽の光の当たるところでcontributorをねぎらう習わしはRailsやRubyのいいところですね」
オープンソースに限らず、面倒な仕事をやってくれているありがたい人に大勢の人が無意識に甘えてしまい、リクエストや苦情が押し寄せて台無しになってしまうのをよく見かけますね。この残念な現象にうまい名前を付けたい気持ちです。
Rails: 今週の改修
5.1.3リリース直後&夏休みのためかRails公式の改修情報も夏枯れなので、気になるものをいくつかチェックしてみました。網羅的なのはy-yagiさんにおまかせして、閉じてないissueを少し見てみました。
進行中→merge: adapter_is?
でアダプタ名を返すよう修正
# https://github.com/rails/rails/pull/30287 より
def adapter_is?(*adapter_class_symbols)
- adapter = ActiveJob::Base.queue_adapter.class.name.demodulize.chomp("Adapter").underscore
- adapter_class_symbols.map(&:to_s).include? adapter
+ adapter_class_symbols.map(&:to_s).include? ActiveJob::Base.queue_adapter_name
end
?
付きメソッドが論理値でないものを返しているように一瞬見えたのですが、#include?
の結果は論理値ですね。失礼しました。
つっつきボイス: 「昼間ツイートで見かけたのが、もうmergeされてるw」
進行中→解決: スコープ付きのbelongs_to
でjoin
されない
再現コードがみっちり付いていますが、長いので一部だけ。
# https://github.com/rails/rails/issues/30284 より
class Photo < ActiveRecord::Base
belongs_to :photographer
belongs_to :imageable, polymorphic: true
belongs_to :post,
-> { joins(:photos).where(photos: { imageable_type: 'Post' }) },
foreign_key: :imageable_id,
optional: true
belongs_to :comment,
-> { joins(:photos).where(photos: { imageable_type: 'Comment' }) },
foreign_key: :imageable_id,
optional: true
scope :attached_to_posts, -> { joins(:post) }
scope :attached_to_comments, -> { joins(:comment) }
end
つっつきボイス: 「むむ、belongs_to
とscope
の両方でjoin
使ってるのか」「polymorphicのbelongs_toって普通はas: :imageable
みたいに書くんじゃなかろうか」「普通こういう書き方はしないですねー」
翌日見てみると、kamipoさんが回避方法↓を示して解決→closeしていました。
# https://github.com/rails/rails/issues/30284#issuecomment-323073496 より
class Photo < ActiveRecord::Base
def post
if association(:post).loaded?
super
else
imageable if imageable_type == "Post"
end
end
def comment
if association(:comment).loaded?
super
else
imageable if imageable_type == "Comment"
end
end
end
今気づきましたが、再現コードがcontrived(わざとらしい)と形容されているので、やはり問題再現のための無理やりコードですね。
RubyでStrong Parametersをfunctionalに書いてシンプルにしてみたった
最近のRailsでおなじみのstrong parametersをあえて関数型言語っぽく書いてみたという記事です。
# いつものstrong parameters
params.permit(:name,
{:emails => []},
:friends => [ :name,
{ :family => [ :name ],
:hobbies => [] }])
# 関数型風味
friend = hash_of.(name: scalar,
family: hash_of.(name: scalar),
hobbies: array_of.(scalar))
hash_of.({ name: scalar,
emails: array_of.(scalar),
friends: array_of.(friend)})
つっつきボイス: 「確かに下のコードの方がわかりやすくはある」「宣言的だし」「.()
でつなぐ記法は慣れてないとドキッとするw」「脳をカリー化に切り替えるコストがなかなか大きいw」「なおJavaでreflectionやるのはとってもつらいでござるよ」
「でもまあここまでするんだったら、strong parametersのためのもうちょっとマシなDSLを定義した方がよいとは思う」「functionalって日本語にすると長ったらしくなって面倒ですw: 関数型言語風とか」
「Rubyのカリー化はProc#curry
か」「そういえば昨年のTechRacho記事でRubyのカリー化の話題出てましたね、私がTechRachoに参加する直前ぐらい」
そこからJSON Schemaの話題になりました。
「strong parameterをJSON Schema↓あたりで静的に書ける方が好きだなー: 誰が見てもわかるし」「コメント書けるJSON5もはよ」
{
"title": "Person",
"type": "object",
"properties": {
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
},
"age": {
"description": "Age in years",
"type": "integer",
"minimum": 0
}
},
"required": ["firstName", "lastName"]
}
参考
- JSON Schema: json-schema.org
- JSON5: json5.org
- Railsガイド: strong parameters
箸休め: 夏休みにRailsコミット観察日記はいかが
Rails初心者やジュニア開発者、学生さんが一皮むける方法のひとつとして、y-yagiさんのrails commit log流し読み風にRailsコミット観察日記的なものをつけてみるといいかもしれません。最初のうちは「この行が何なのかさっぱりわからん」「すっげえ量」「みんなどうやって追っかけてるんだろう」ぐらいで十分だと思います。
いきなりRailsのcommitを開くと気後れするので、Watchボタン↓で更新メールを自分に飛ばすとか、RSSで読むとかRSSをSlackに飛ばすとかで楽しましょう。
日記をどこにどう書くかはまったく好き好きでよいと思いますが、私としては適当なブログサイトに観察日記を独り言っぽく書き捨てるのがおすすめです。ローカルPCや非公開ブログより、多少人から見える方が継続しやすいようです。
検索で見つかるのは恥ずかしいという内気な方は、タイトルを日付だけにしておけば検索エンジンのクローラーもあきれて通り過ぎてくれますので安心です。ブログが観察日記専用なら重複コンテンツでクローラーからペナルティ喰らっても問題ありません(会社のブログでやるときには重複コンテンツにならないよう注意しましょう)。
y-yagiさんのように雨の日も風の日も盆暮れ正月も更新を続けるのはめったにできることではありませんが、はずみに乗って週一程度コミットを眺める習慣が付いたらそれだけでも儲けものですね。
TypeScriptを新しいRails + Yarnで使う手順
- 記事: Add TypeScript support to Ruby on Rails - A quick and hacky example
- サンプルアプリ: Demo-TypeScript-Support-to-Ruby-on-Rails
お盆のせいか、TypeScriptをRailsで使いたいという声が遠くの方からかすかに聞こえてきたので、新しめの記事を探してみました。
# yizeng.me より
class HelloWorld {
private name: string;
constructor(name: string) {
this.name = name;
}
print() {
alert(`Hello World, ${this.name}!`);
}
}
new HelloWorld('John Doe').print();
つっつきボイス: 「最近のRailsでTypeScriptしたい人には助かりそう」「TypeScriptで型定義しておけばどんなによかったろうというRails案件があったでござるよ...」「TypeScriptそんなに難しくないですヨ」
「以前だったらtypescript-rails gemみたいなのをインストールするところですね」「今のRailsはJSをgemでインストールしない方向に変わったから、*-rails
みたいなJS系gemは基本使わない」
「CoffeeScriptはRailsビューにインラインでも書けるけど、TypeScriptもインラインでビューに書けるのかな?できそうだけど」
最近はちょっぴり落ち着き気味らしいTypeScript人気ですが、今さらのように少し眺めてみると、ブサメンコードでの殴り合いが日常茶飯事の修羅JS界では異色の端正さと、ガツガツマウントを取りに行かない育ちのよさをほんのりと漂わせていて、なかなかのイケメンコードに見えてきた気がします(個人の感想です)。どうか悪魔合体しませんように。
function classDecorator<T extends {new(...args:any[]):{}}>(constructor:T) {
return class extends constructor {
newProperty = "new property";
hello = "override";
}
}
@classDecorator
class Greeter {
property = "property";
hello: string;
constructor(m: string) {
this.hello = m;
}
}
console.log(new Greeter("world"));
参考
Rubyで連結リスト(RubyFlowより)
アルゴリズムの授業でおなじみの連結リストをRubyで実装して配列と比較してみたそうです。
つっつきボイス: 「ベンチマークもやってるな」「arrayと連結リストで計算量の比較もやってますね」「ほむほむ、今pryで適当にarrayにappend
してみたけど、相当な回数繰り返してもarrayのobject_id
変わらないなー: Rubyだとどのぐらいappend
したらarrayオブジェクトが再生成されるかな...れれ?」
a = [1,2,3,4,5,6,7,8]
def insert(arr, item, pos)
tmp = arr[pos]
arr[pos] = item
arr.replace(arr[0..pos] + [tmp] + arr[pos+1..-1])
end
insert(a, 99, 3)
p a
「あー、このコード、むりやりarrayを再生成させておる↑これはいかんなー」「それじゃ比較の意味ないですね」
「そもそも、Rubyのような高度な言語でデータ構造とかメモリアロケーションみたいなテーマを扱うのは無理ある」「確かに、Rubyみたいに最適化の進んだ言語でアルゴリズムを再現しても、内部を知らないと参考にならなさそう」「やるならもっとマシン寄りの言語でね♡」
問題解決に再帰を使ったの久しぶりすぎ
再帰関数がうまくはまった事例を紹介する記事です。
# http://blog.arkency.com/that-one-time-i-used-recursion-to-solve-a-problem/ より
class Calculator
def initialize(current_time:, event_starts_time:)
@current_time = current_time
@event_starts_time = event_starts_time
@eb = ExponentialBackoff.new(12.hours, 1.month)
end
def compute
sub_compute(@current_time, @event_starts_time, 0).sort
end
private
def sub_compute(left_boundary, right_boundary, current_level)
duration = @eb.interval_at(current_level).seconds
available_time = right_boundary - left_boundary
if available_time >= 3*duration
[
new_left = left_boundary + duration,
new_right = right_boundary - duration,
] + sub_compute(new_left, new_right, current_level+1)
elsif available_time >= 2*duration
[
left_boundary + available_time/2,
]
else
[]
end
end
end
つっつきボイス: 「再帰って今でもプログラミングの授業で教えますよね?」「もちろん」「うんと昔に初めて再帰アルゴリズムを知ったときはすごく感激したんですが、その後『再帰は遅い』みたいな感じで避けられてる感」
「再帰はきれいに問題解決したときはキモチイイけど、使い所に気をつけないと計算量爆発するからw: stack level too deepとか」「無理矢理使うのは感心しないですねー」「parserみたいなところで再帰を使うことはあるので、ActiveRecordのArelあたりでもたぶん使われてる」
- 参考: Wikipedia-ja 再帰
RubyのWeakRefライブラリ
テストでガベージコレクション(GC)するのにRubyのWeakRefを使ったそうです。
# http://www.bpietraga.me/ruby-weakref-and-running-garbage-collection-in-tests/ より
require 'rspec'
require 'weakref'
class Modifier; end
class Communicator
def initialize
@modifier_object = modifier_object
end
def call
return 'Modifier object was found' if @modifier_object
'No modifier object found'
end
private
def modifier_object
ObjectSpace.each_object.find { |obj| modifier?(obj) }
end
def modifier?(obj)
obj.class == Modifier
rescue
false
end
end
RSpec.describe Communicator do
it "modifier object in object space" do
GC.start
WeakRef.new(Modifier.new)
expect(Communicator.new.call).to eq('Modifier object was found')
end
it "modifier object not found" do
GC.start
expect(Communicator.new.call).to eq('No modifier object found')
end
end
つっつきボイス: 「WeakRefって何だろうと思って」「今のRubyのGCってどの方式だったっけ?」
「世代別だったと思います」「お、Ruby trunkにあった」
私は何となくガベコレと呼んでましたが、ちょい古いかも。
参考
- Rubyリファレンスマニュアル WeakRef
- Wikipedia-ja: 弱い参照
- RubyのGCと仲良くしたい〜WeakRefオブジェクトを削除するぞ編〜
- Wikipedia-ja: 世代別ガベージコレクション
Docker化したRailsアプリをデバッグするコツ10
- 504 Gateway ErrorはALBがコケてるかも
- サーバー再起動後にはdev環境でURLをチェック
- Healthチェック
- Application Docker Logsをチェック
df
でディスク容量チェックhtop
でCPU/メモリ使用量をチェック- コンテナごとのステータスをチェック
- timber.ioでログを見やすく
- Error loggerをチェック
- 結論: コンテナは全部チェックしる!
つっつきボイス: 「うん、どれも普通w」「普通なのでデバッグやるなら当然チェックするということですね」
「ところでこのtimber.ioってカントリー風味でちょっと面白いw」「ちなtimberは『丸太、材木』です」
今気づきましたが、logは本来『丸太』なので、timberと掛け言葉になってるんですね。
「Rubyで#interpose
」、自分もやってみた
www.virtuouscode.comより
以前のウォッチでも紹介したClojure's interpose in Rubyを受けた記事です。
# http://www.virtuouscode.com/2017/08/02/riffing-on-interpose-in-ruby/ より
module Interpose
refine Enumerable do
def interpose(*)
end
end
end
つっつきボイス: 「refinement
使ってる」「Enumerable
に品よくパッチを当てるならこうでしょ」
「うん、この解説かなり頑張って書いてある」「以前の記事よりもよく書けてるっぽいです」「step by stepで読み進めると勉強になりそう」
Railsのテストでログを吐かないようにして6%速くなった
とっても短いのですぐ読めます。
# https://jtway.co/speed-up-your-rails-test-suite-by-6-in-1-line-13fedb869ec4 より
unless ENV['RAILS_ENABLE_TEST_LOG']
config.logger = Logger.new(nil)
config.log_level = :fatal
end
つっつきボイス: 「log出力はまあ重いから止めれば速くなるw」「昔のLinux環境なんかで、ファイルサイズが2GBを超えると追記が死ぬほど重くなったりするなんてことも稀に良くあった」
Rubygem
public_activity: モデルのactivityをトラックするgem
- リポジトリ: chaps-io/public_activity
PAINLESS ACTIVITY STREAMS IN RAILSという記事で見つけました。★2400級で、コミットは現在も増えています。
つっつきボイス: 「おー、これもBPSのmangarebornでほぼ同じことやってたなー: 設計もだいたい似てる」「おおー」「Rails 1ぐらいの時代でしたね」
「こういうgemがあるなら使うのはありだと思いますが、気をつけないとactivityテーブルの容量がめちゃめちゃでかくなるので適当なタイミングで消さないと死にますよw」
batch-loader: N+1問題用gem
- 元記事: Batching – A powerful way to solve N+1 queries every Rubyist should know
- リポジトリ: exAspArk/batch-loader
図の書き方が面白かったのと、batch-loader
という名前でわかってもらえるのかが気になったので。
# https://github.com/exAspArk/batch-loader より
def load_posts(ids)
Post.where(id: ids)
end
posts = load_posts([1, 2, 3]) # Posts SELECT * FROM posts WHERE id IN (1, 2, 3)
# _ ↓ _
# ↙ ↓ ↘
users = posts.map do |post| # U ↓ ↓ SELECT * FROM users WHERE id = 1
post.user # ↓ U ↓ SELECT * FROM users WHERE id = 2
end # ↓ ↓ U SELECT * FROM users WHERE id = 3
# ↘ ↓ ↙
# ¯ ↓ ¯
puts users # Users
つっつきボイス: 「お、この間のTechRacho記事↓で取り上げてたrender_async
gemとコンセプトがよく似てる: Ajaxではなくビューのレベルでやるところが違うくらいで」
「めちゃめちゃでかいデータセットに対して扱うとき、データをlazyに小分けしてビューで逐次レンダリングして、表示できるものから先にデータを返していく」「なるほど、そう思うと上のベルトコンベア写真もコメントの図もbatch-loaderという名前も一貫してますね」
「最近のブラウザは賢くて、レスポンスが完結してなくてもrenderingできるので」
「記事もいいですねー」
JavaScript
pretty-algorithms: アルゴリズム集
- リポジトリ: jiayihu/pretty-algorithms
二分木探索などの基本的なアルゴリズムをJavaScriptで書いています。ちょっと珍しい気がしたので。
つっつきボイス: 「大学の先生が授業で使ったりするのに便利かな」「Yahoo知恵袋で必死で答えを教えてもらおうとしている学生とかにもw」
RDBMS
2017年後半は各種RDBMSのメジャーアップデートがリリースラッシュ
morimorihogeさんがSlackに投下した記事で、2017年後半はRDBMSのメジャーリリース予定が目白押しだったことを思い出しました。
ひとまずリリースノートをリンクしておきます。皆さまもお備えあれ。
Trdsql: CSVにSQLでクエリをかけられるツール
morimorihogeさんがSlackに投下してくれました。CSVやタブ区切りテキストなどにSQLクエリをかけられるというのがちょっと驚きです。
$ trdsql "SELECT c2,c1 FROM test.csv"
Orange,1
Melon,2
Apple,3
番外
MapChart: プレゼン作成に便利な白地図
- サイト: mapchart.net
国や地域の色の塗り分けをかっこよくやってくれます。プレゼンがはかどります。
つっつきボイス: 「おおーこれ凄い!」「日本の都道府県とかも塗り分けできるし」「夏休みの宿題がはかどりそう」「Googleマップくさくないのが新鮮」「世界征服もはかどる」「これでAPIがあればなー」
今日も元気にP≠NP
[B!] arxiv に P≠NP 問題を解決した論文が投稿される | スラド サイエンス https://t.co/kYDRknRUAx
— id:advblogのはてなブックマーク (@advBookmark) August 17, 2017
暑中見舞い代わりに
めちゃかっこいい
「車好きだった祖父に快適なドライブを」 お盆に作られた精霊馬が野菜とは思えないかっこよさ - ねとらぼ https://t.co/oVrle1dGhm @itm_nlabから pic.twitter.com/a4Zt3MquGv
— ねとらぼ (@itm_nlab) August 13, 2017
今週は以上です。
バックナンバー(2017年度)
- 週刊Railsウォッチ(20170804)Rails 5.1.3と5.0.5が正式リリース、GitHubでローカライズ基盤サービス、正規表現で迷路を解くほか
- 週刊Railsウォッチ(20170623)gemを見極める7つのコツ、mixinがよくない理由、重いページをrender_asyncで軽減ほか
- 週刊Railsウォッチ(20170616)railsdiff.orgはアップグレードに便利、RubyのDSLとかっこの省略、TerraformをRubyで制御ほか
- 週刊Railsウォッチ(20170609)ついにtherubyracerからmini_racerへ、注意しないとハマるgem、5.1でのVue.jsとTurbolinksの共存ほか
- 週刊Railsウォッチ(20170602)チームが喜ぶ19のgem、Bundler 1.15が高速化&機能追加、Deviseに挑戦する新認証gem「Rodauth」ほか
- 週刊Railsウォッチ(20170512)Rubyの不思議な挙動「シャドウイング」、コードレビュー作法を定めるDanger gemほか
- 週刊Railsウォッチ(20170428)Rails 6.xでの’#form_for’と
#form_tag
廃止決定のその後、deviseの5.1対応はこれから、ほか - 週刊Railsウォッチ(20170421)RailsConfが来週アリゾナで開催、コントローラを宣言的に書けるdecent_exposure gemほか
- 週刊Railsウォッチ(20170414)サーバーを危うくする1行のコード、PostgreSQL 10の新機能ほか
- 週刊Railsウォッチ(20170407)N+1問題解決のトレードオフ、Capybaraのテスト効率を上げる5つのコツほか
- 週刊Railsウォッチ(20170331)PostgreSQLの制約機能を使えるRein gemはビューも使えるほか
- 週刊Railsウォッチ(20170324)Ruby 2.4.1リリース、GAEがついにRubyに対応、このgemがないと生きていけない27選ほか
- 週刊Railsウォッチ(20170317)Railsパフォーマンスチューニング本、DBレコード存在チェックの最速メソッド、RubyのUnicode正規化ほか
- 週刊Railsウォッチ(20170310)クールなDocker監視ツールCtop、RailsがGoogle Summer of Code 2017に正式参加、Unicode 10.0.0ドラフト発表ほか
- 週刊Railsウォッチ(20170303)5.0.2正式リリース、メタプログラミングに懲りた話、bundler 1.12のバグ、すぐ試せるWebアノテーションほか
- 週刊Railsウォッチ(20170227)Rails 4.2.8リリース、SHA-1コリジョンアタック、便利なハッシュ変換ツールほか
- 週刊Railsウォッチ(20170217)Rails 4.2.8.rc2リリース、Ruby 2.4正規表現とActiveSupportのnormalizeほか
- 週刊Railsウォッチ(20170210)JRubyやRubiniusの配列への追加はスレッドセーフではないほか
- 週刊Railsウォッチ(20170203)AnyLogin gemで開発中に楽々再ログイン、イベント数ベース課金の監視サービスRollbarほか
- 週刊Railsウォッチ(20170127)わかりやすいAWSサービス名、Rails DBは便利、TruffleRubyの驚異的速度ほか
- 週刊Railsウォッチ(20170120)Ruby 2.5.0 devリリース、古いMySQLのサポート終了、uniqメソッドが削除ほか
- 週刊Railsウォッチ(20170116)Ruby 2.4の詳細、範囲指定したsumメソッドは速い、rescueの挙動を動的に変更ほか
- 週刊Railsウォッチ(20170110)ReactをRailsに置き換える、Ruby 2.4の新機能ほか
今週の主なニュースソース
ソースの表記されていない項目は独自ルート(TwitterやRSSなど)です。