週刊Railsウォッチ(20191015)スライド「Rails Performance issues and Solutions」を見る、dirtyに*_previously_was が追加、Sidekiq 6.0.1ほか

こんにちは、hachi8833です。台風前のつっつきでしたので、エントリを減らし気味にしてみました🙇。


つっつきボイス:「jnchitoさんは関西の方でしたね☺️」「mapで風速を秒速から時速に変換してる」

  • 各記事冒頭には⚓でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
  • 「つっつきボイス」はRailsウォッチ公開前ドラフトを(鍋のように)社内有志でつっついたときの会話の再構成です👄
  • 毎月第一木曜日に「公開つっつき会」を開催しています: お気軽にご応募ください

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

今回は公式情報を中心に見繕いました。

なお、6.0.1マイルストーンも見てみましたが、「再現できない」「自分のコードが間違ってた」でcloseされているケースがいくつか見当たりました。

新機能: dirtyトラッキング用 *_previously_wasを追加

なおマージされたのは8/2です。

# 同PRより
pirate.update(catchphrase: "Ahoy!")
pirate.previous_changes["catchphrase"] # => ["Thar She Blows!", "Ahoy!"]
pirate.catchphrase_previously_was # => "Thar She Blows!"
# activemodel/lib/active_model/dirty.rb#L125
    included do
      attribute_method_suffix "_changed?", "_change", "_will_change!", "_was"
-     attribute_method_suffix "_previously_changed?", "_previous_change"
+     attribute_method_suffix "_previously_changed?", "_previous_change", "_previously_was"
      attribute_method_affix prefix: "restore_", suffix: "!"
    end
...
+   # Dispatch target for <tt>*_previously_was</tt> attribute methods.
+   def attribute_previously_was(attr_name) # :nodoc:
+     mutations_before_last_save.original_value(attr_name.to_s)
+   end

API: ActiveModel::Dirty
参考: 1.4 Dirtyモジュール — Active Model の基礎 - Rails ガイド


つっつきボイス:「またdirtyに新しいメソッドが生えるのね😆」「DHHが自分でツイートしていたような気がします」

探しましたがDHHのツイートはありませんでした😅。代わりに以下を貼っておきます↓。

新機能: MySQLでmatches_regexdoes_not_match_regexpが使えるようになった

# 同PRより
users = User.arel_table;

# 全gmailユーザーを検索
users = User.arel_table; User.where(users[:email].matches_regexp('(.*)\@gmail.com'))

# gmail以外の全ユーザーを検索
users = User.arel_table; User.where(users[:email].does_not_match_regexp('(.*)\@gmai
# activerecord/lib/arel/visitors/mysql.rb#L51
+       def visit_Arel_Nodes_Regexp(o, collector)
+         infix_value o, collector, " REGEXP "
+       end
+
+       def visit_Arel_Nodes_NotRegexp(o, collector)
+         infix_value o, collector, " NOT REGEXP "
+       end

つっつきボイス:「ActiveRecordで#matches_regexpを使った正規表現比較がMySQLでもできるようになった🎉」「今までもwhereの中に書いたりしてたけど、エスケープしてくれるのがありがたい😋「PostgreSQL版の実装は前からあったみたいで、今回はMySQLでも使えるようにしたそうです」

調べてみるとPostgreSQL版は2年前に入っていました↓。

# https://github.com/rails/rails/blob/master/activerecord/lib/arel/visitors/postgresql.rb#L29
        def visit_Arel_Nodes_Regexp(o, collector)
          op = o.case_sensitive ? " ~ " : " ~* "
          infix_value o, collector, op
        end

        def visit_Arel_Nodes_NotRegexp(o, collector)
          op = o.case_sensitive ? " !~ " : " !~* "
          infix_value o, collector, op
        end

「SQL文の中で正規表現が使いたくなることってたまにありますよね?」「今どきのRDBではたいてい使えますけど😋」「あ、SQLite3で正規表現をちょっとだけ使おうとしたときが割と面倒でした😆」「SQLite3にはなさそう😆」「一応あるにはありました↓」

参考: SQLite で正規表現を使う - しょぼんメモリ (´・ω・`)

「まあRDBの正規表現を使いすぎるとちゃんとした速度が出なくなったり、インデックスが効いたり効かなかったりすることもあるので微妙ですけど😆」「そうですよね」「コレーション(照合順序)とかも影響する可能性ありそうですし😅」

参考: PostgreSQL 11.5ドキュメント 23.2. 照合順序サポート

joinsのorderをできるだけ維持するよう修正

修正量が多めだったのでソースは貼りませんでした。


つっつきボイス:「最近kamipoさんたちが苦しみ続けていたjoinsのorderの件が『できるだけ維持する』方向でひとまず収束したようです」「ここはたしかに厄介な部分…😅」「Active Recordのオブジェクトとしてどう解釈されるかまで考えたうえでSQL文も見ないといけないのはつらい🥺」

RackのMigration::CheckPendingFileUpdateCheckerを使うようにしてマイグレーションのパフォーマンスを大きく改善

ここからはマージされたプルリクから見繕いました。最近は大半がドキュメントの微修正です。

# 改修前
$ be ruby benchmark.rb
Warming up --------------------------------------
   CheckPending#call    11.000  i/100ms
Calculating -------------------------------------
   CheckPending#call    135.510  (±12.5%) i/s -    671.000  in   5.083931s
# 改修後: file_watcher == FileUpdateCheckerの場合
$ be ruby benchmark.rb
Warming up --------------------------------------
   CheckPending#call    34.000  i/100ms
Calculating -------------------------------------
   CheckPending#call    348.063  (±18.1%) i/s -      1.666k in   5.024624s
# 改修後: file_watcher == EventedFileUpdateCheckerの場合
$ be ruby benchmark.rb
Warming up --------------------------------------
   CheckPending#call   128.936k i/100ms
Calculating -------------------------------------
   CheckPending#call      1.884M (± 2.5%) i/s -      9.412M in   5.000561s

従来はlast_migration.mtimeの値で変更を監視していたが、ActiveSupport::FileUpdateCheckerEventedFileUpdateChecker(新しいアプリではこちらがデフォルトになる)を用いてパフォーマンスを大幅に向上させた。
同PRより大意


つっつきボイス:「この間も話に出たファイルウォッチャー(ウォッチ20190930)を使ってマイグレーションのpendingチェックを速くしたそうです」「お〜なるほど、これでファイル更新チェックのために毎回全なめしなくてよくなった😋」「pendingチェックたしかに今まで遅かったですね」「productionも含めてRailsサーバーの起動が速くなりそう👍」

「この#37395と同じお題で以前に#29759↓でチャレンジしたときはうまくいかなかったのを再挑戦して今度はうまくいったそうです」「こういうのはどうやってテストするかという問題もありますし、Railsはマルチワーカーで動くからそこでもちゃんと動かないといけないでしょうし☺️」

(ドキュメント)autosaveの関連付けの振る舞いについて注意点を追加

レコード自身が変更された場合、autosaveは永続化済み関連付けレコードでのみトリガーされる。これは循環した関連付けバリデーションによるSystemStackErrorから保護するのが目的。例外が1つあって、カスタムのバリデーションコンテキストが使われていると、関連付けられたレコードのバリデーションが常に発火する。
同PRより大意


つっつきボイス:「APIドキュメントに注意事項が1つ追加されていました」「circular association validationって😆」「循環参照があるとautosaveの挙動がおかしくなるでしょうね☺️」「ただしカスタムのバリデーションコンテキストが使われているとバリデーションが常に発火すると」

参考: 4.3.2.2: has_manyautosave — Active Record の関連付け - Rails ガイド

# 5a3e34eより
  def test_validations_still_fire_on_unchanged_association_with_custom_validation_context
    firm_with_low_credit = Firm.create!(name: "Something", account: Account.new(credit_limit: 50))

    assert firm_with_low_credit.valid?
    assert_not firm_with_low_credit.valid?(:bank_loan)
  end

5a3e34ecreate!でやってるこのあたり↑がそうかな」「おぉ?」「中でAccount.newしているものがsaveされないとidが確定しないからcreate!できなくなりますね」「あ〜なるほど!」「こういうのがカスタムバリデーションコンテキストでのautosaveということだと思います☺️: 中のAccountが外のFirmにhas_manyしているときは、firm.account_idをセットするために中のものから先に作らないといけないのでAccount.newが自動でsaveされると」「こういう状態を何て言えばいいんでしたっけ?😅」「循環でもデッドロックでもない、普通の依存関係ですね☺️」

Rails

スライド: amatsudaさんの「Rails Performance issues and Solutions」


つっつきボイス:「この間の公開つっつきでこちらのスライドを取り上げるのを忘れていました😅」「そうそう、この間の銀座Rails#13↓でamatsudaさんが発表したRailsパフォーマンス話もこれに含まれていると思います😋」「スライドはその後のRubyConf Indonesia 2019でのものだそうです」「つか銀座Railsのスライドはそっち用のドラフトだったのかも😆」「銀座Railsのときにも資料書いてる途中だって言ってましたね☺️」

銀座Rails#13で「出張Railsウォッチ」発表させていただきました

「このスライドでもRails 6でのrails newでは--skip-spring--skip-bootsnapしてますが↓、銀座Railsのときにも--skip-action-textでAction Textをスキップすることが重要という話がありましたね😆」「え?😅」「今のAction Textが半端なく重いのでとりあえず無効にしておきましょう、だそうです😆」

「銀座Railsのときにマジで面白かったのはこの辺の計測の話でした❤️」「どんなお話でした?」「まあ実際のアプリでベンチマーク取るときはcurlとかでやればいいんですけど、Railsフレームワークのどこにボトルネックがあるのかを調べるときには、こんなふうに↓イニシャライザで直接モンキーパッチを当ててやる方がいいということでした」「おぉ〜!」「こうすればRackの処理の重さとかに影響されなくなるので純粋にRailsコードの速度を測れるようになるからいいよって😋」「これいいノウハウですね😍」「ここではprependで直接差し込んでます」

「Apache Bench(ab)とかで測定すると、どうしてもRails以外のボトルネックも出てきたりしてしまいますが、この方法ならRailsのコードだけにフォーカスできますね👍」「あとはアタッチする場所を少しずつ変えて試す↓: パッチのコードは他の場所でもほぼそのまま使い回せるので、うまい方法だと思います😋」「いいですね〜😋」

参考: Apache Benchでサクッと性能テスト - Qiita

「次がRailsのアロケーションを削減する話」「『先週の改修』でもamatsudaさんがやってるのを見てきましたね」「こうやってProf.memしてプロファイラの結果を眺めて、これはちょっと多くね?と思ったところをひたすら地道に直していくというのをやってるそうです↓」「ふむぅ」

「そうそう、使ってないはずのAction Textエンジンがなぜかいるという話も↓😆」「おおっと😆」

「その修正方法はというと、require 'rails/all'をやめてAction Textだけを除いたものを自力で書くと↓🤣」「🤣」「Action Textをrequireするだけで重くなるからRails 6ではこうするとこれだけアロケーションが減って速くなるよと」「何ということでしょう😆」


rails newする段階でAction Textを入れないようにする方法ってありますよね?🤔」「あります」「でもたぶんapplication.rbでrequire 'rails/all'するとAction Textも入っちゃうんだと思います: というのもRailsのgemspecにはAction Textも入ってるはずなので、Gemfileでrequire "rails"と書かれている状態でbundle installした段階ではAction Textのgemも入ってくるはずで、その状態でrails newするとapplication.rbでrequire 'rails/all'となって入ってきちゃうと思います」「あ〜」

後で、ごく最近のRails 6で--skip-action-textなどを指定してrails newしたもので見てみるとapplication.rbでは自動的に除外されていますね↓😋。rails newで何もスキップしない場合はrequire 'rails/all'になります。rails newした後から機能を外す場合は自分でrequire周りを変える必要がありますね。

require_relative 'boot'

require "rails"
# Pick the frameworks you want:
require "active_model/railtie"
require "active_job/railtie"
require "active_record/railtie"
require "active_storage/engine"
require "action_controller/railtie"
# require "action_mailer/railtie"
# require "action_mailbox/engine"
# require "action_text/engine"
require "action_view/railtie"
# require "action_cable/engine"
# require "sprockets/railtie"
require "rails/test_unit/railtie"

参考: Rails 6.0.0 performance regression because of ActionText::Engine hook · Issue #36963 · rails/rails — open

「Action Textはrequireから外さないとアロケーションされてしまうらしい🤔」「amatsudaさんが#36963↑を投げてくれて『Rails 6.0.1で直ることを期待』と」「Action Text以外のオプション機能についてはrequireから外してもなぜかアロケーションは変わらないと」

↓こちらのissueも関連してそうです。

参考: ActionText forces all apps to include an ActionController::Base subclass · Issue #37183 · rails/rails — open


「後は細かいところだと=~よりmatch?の方が速いとか↓」「そういえば今のRubyはmatch?の方が速いんでした」「match?は余分なオブジェクトに触らない分速いとかそんな感じ」

「ハッシュもHash#mergeより添字アクセスのHash#[]=の方が速い↓」

「同じくHash#fetchよりHash#[] || defaultの方が速い↓」「上もそうだけど、前者はメモリがアロケーションされるけど後者はされないのね」「Hash#[]はCRubyのコアのところに直接つながっているはずだけど、Hash#mergeHash#fetchはメソッド呼び出しだから、たぶん仮引数代入とかが発生するんじゃないかしら🤔」「おぉ」

「まさにマイクロオプティマイゼーションを積み上げていく作業😳」「塵も積もれば5〜10%のアロケーション削減が見込まれると🎉」「このスライドはじっくり追いかけていくといろいろ発見がありますね❤️」

「この辺はテンプレートエンジンの話↓」「hamlは速いぜと😋」「k0kubunさんも記事にしてたヤツですね(ウォッチ20190925)」「stringの式展開にすると速いという話とか」

「amatsudaさんによると実はI18nが重いんですよ↓」「おぉ?」「I18nだけは式展開にできないのでどうしてもメソッド呼び出しが残っちゃう」「なるほど!」

「なのでロケールごとにI18nのキャッシュを作って高速化しようとしてるそうです↓: 銀座Railsで見たときはまだ作業中と言ってたかな」「これもすごく有用な話ですね😋」「こういう積み重ねでメモリアロケーションをじわじわ減らしていると」「すげ〜!」「Railsはメモリをめちゃ食うという印象があったりするので、こういうところが改善されていくのはいいですね〜☺️」


「上のツイート↑はこの間のウォッチでは裏を取れなくて見送った話でした」「そうそう、Ruby 2.6.4だとMonitor#synchronizeでRailsのベンチマークが遅くなるそうです↓」

参考: class Monitor (Ruby 2.6.0)

Rails 6のAR associationとscopingの変更

ruby-jp Slackで知りました。


つっつきボイス:「上の記事はもともと論理削除が使われていたコードのつらみから始まったとのことで、今日はつっつきに出られないkazzさんにこの記事を見せたら苦笑いしてました😅」

しかし、Rails 6では…
仕様が変更された為、先程のコードはそのままでは動きません。具体的には、

Blog.not_deleted.scoping do
  BlogComment.where(blog_id: 1).blog
end

nil を返しません。 BlogComment.blog のAssociation解決時に実行される Blog モデルへのSELECTクエリへのスコープがリセットされ、deleted_at IS NULL の条件が消える為です。
同記事より

参考: Association loading isn’t to be affected by scoping consistently by kamipo · Pull Request #35868 · rails/rails

「Rails 6では上のように変わってたそうです」「へ〜、たしかにassociationのタイミングで違うものを返されるとビビるからマジ止めてほしい😭」「associationの読み込みはdefault_scopeでは有効だけどunscope以外の普通のスコープだと有効じゃなくなったとは😳」「そういえばRailsアップグレードガイド↓でこの変更を翻訳した覚えがありませんでした」

参考: Rails アップグレードガイド - Rails ガイド

「まあscoped chainはやりすぎるとつらくなるし😢」「やっぱこういうのはテストを書いておくべきだな〜: でないとこういうbreaking changesが起きたときに死ぬ😇」「踏んだときに原因がわかりにくそう😅」

「記事はやむを得ずdefault_scopeで対応することにしてますね」「default_scope使わないぞキャンペーンもしつつ😆」「default_scopeは止めた方がいいかと😆」

Railsのdefault_scopeは使うな、絶対(翻訳)


以下はつっつきの後で見つけたツイートです↓。

Sidekiqが6.0.1で高速化(Ruby Weeklyより)


つっつきボイス:「10〜15%速くなったはず、とありますね」「タグを付けられるようになってる↓」「Pro版だとこれで絞り込めるそうです」

# changelogより
class MyWorker
  include Sidekiq::Worker
  sidekiq_options tags: ['bank-ops', 'alpha']
  ...
end

find_jobもかなり速くなってる↓」

zscan 0.179366 0.047727 0.227093 ( 1.161376)
enum 8.522311 0.419826 8.942137 ( 9.785079)

「結局Sidekiqをナマで使うことになるのかな〜: Active Job越しにやると機能が足りなかったりしますし😅」「そんな雰囲気ですね」「Rails way的には本来Active Jobでジョブワーカーを抽象化するんですけど、ジョブワーカーの種類によって機能が違うから特定のジョブワーカーの機能を使おうと思うとActive Job経由できれいにやろうとするより生のSidekiqを使うことになりそうかな〜🤔」「ラッパー越しだと靴の上から足を掻くみたいになっちゃうんですね😳」「単純な作業ならラッパー越しでもいいんですけど、ジョブの制御までやり始めるとそうなりがち😢」「うーむ」

「ジョブで名前空間を使いたいとかプライオリティ付きのキューとかは、ジョブワーカーによってできるものとできないものがあったと思いますし」「ジョブワーカーというとこのsidekiqの他にdelayed_jobと、あと何だっけ?」「思い出せない😅」「最近sidekiq使うこと多いし😆」「あ、resqueか!」

「sidekiqのリリースノートを見ると、なぜか『ダークモードに対応』ってありますけど😆」「sidekiqのWeb UIには割とお世話になりますし、マウントするだけでWeb UIを使えるのは便利😋」「『もっとイケてるデザイン募集』ともあります🤣」「たしかにあんまりイケてないけど🤣」「まああれで十分ではある☺️」

ARモデル内でクエリロジックを共有する(Ruby Weeklyより)

# 同記事より
class User < ApplicationRecord
  # our class method from above
  def self.can_receive_alerts
    where(receives_sms_alerts: true).
      or(where(receives_email_alerts: true)).
      joins(:alert_configurations).
      distinct
  end

  # our new instance method which builds on the class method
  def can_receive_alerts?
    self.class.can_receive_alerts.where(id: id).exists?
  end
end

つっつきボイス:「自分も先週見つけていた記事でしたがRuby Weeklyに先越されました😢」「コードの再利用ですね☺️: self.can_receive_alertsで作った条件をインスタンスメソッドでちょっと変えてスコープ的に再利用すると」「kazzさんともこの記事で雑談してたんですが今思い出せない😅」「クラスメソッドで使った条件にwhere(id: id).exists?を足してインスタンスメソッドでも使いたいという感じなので、そんなに難しい話ではないですね」「おぉ」「スコープにこういう感じで条件を付けることはよくあるので、インスタンスメソッドでその条件に合っているかを確認するのに同じことをもう一回書かずにやれるよということで☺️」

sprockets 4.0.0がリリース

これもruby-jp Slackで知りました。キーワード引数周りの修正やアロケーション削減、脆弱性修正などが行われました。Ruby 2.5以降のみがサポート対象になりました。


つっつきボイス:「sprocketや〜😆」「Webpackに押されてるのかと思ったらいろいろやってるんですね」「お、JSのSource Mapが使えるようになってるし😋」「3.xにはなかったのか〜」

参考: WTF is a Source Map

  "version":3,
  "file":"application.js",
  "mappings": "AAAA;AACA;AACA;#...",
    "sources": [
      "jquery.source-56e843a66b2bf7188ac2f4c81df61608843ce144bd5aa66c2df4783fba85e8ef.js",
      "jquery_ujs.source-e87806d0cf4489aeb1bb7288016024e8de67fd18db693fe026fe3907581e53cd.js",
      "local-time.source-b04c907dd31a0e26964f63c82418cbee05740c63015392ea4eb7a071a86866ab.js"
    ],
    "names":[]
}

「manifest.jsも対応してるし!欲しかったものが割と増えてる気がする❤️」「デフォルトでES6をサポートですって」

// app/assets/config/manifest.js
//
//= link application.css
//= link marketing.css
//
//= link application.js

「まあES6でやるならWebpackでいいんじゃね?とも思いますが😆」「Sprocketsで十分という人にはありがたそうですね」「RubyのコードでJavaScriptコードを生成したい人はSprocketsを使いたいでしょうね」「というと?」「JavaScriptのコードの中に、パーシャル的にRubyのコードが埋まっているようなコードを書きたいときとか: SprocketsならRubyのコンテキストで処理できるので😋」「おぉ〜」「まあ今となってはあまりやりませんし、manifest.jsがあるならそっちに入れるという手もありますし」

「Rubyエンジニアが多いプロジェクトなら、Rubyが気軽に使えるという意味でSprocketsがいいかも: WebpackにはRubyを処理させられないので(探せばあるかもしれませんが😆)」

「Reactとか使わないんだったらSprocketsでもよさそうですね🤔」「まあそれでもいいんですけど、要はフロントエンドのコードを誰がやるかがポイントかも😆: フロントエンジニアはSprocketsの面倒は見たくないでしょうから彼らが慣れているWebpackの方がいい、とかね」「ふ〜む」「フロントエンジニアにしてみれば、SprocketsのためだけにRailsを勉強するとなるとオーバーヘッドがヤバいですし😆」「たしかに😆」「逆にみんなRailsエンジニアならSprocketsでいいでしょうし、Webpackerがむしろわけわからんかもしれませんし」

Ruby

Ruby 2.7のキーワード引数変更


つっつきボイス:「例の#14183↓がウルトラ長くて私には要約できそうになくて😂」「またしかに😆」「まだ読めてませんが、この記事で端的にまとまってるといいなと願っています🙏: ちなみにこのblog.saeloun.comブログのRuby記事はいいですね😋」

ruby/specに新しいexpectationが追加

これもruby-jp Slackで見かけました。

describe "String#start_with?" do
  it "returns true only if beginning match" do
    "hello".start_with?('hel').should == true
  end
end

つっつきボイス:「ruby/specって何だろうと思ったら、Ruby自身のテストのためのものみたいです」「RSpecライクというか☺️」「それを動かすのがMSpecというツールだそうです」「RSpecをいっぱい書いている人がRubyのspecも書きたい、とかそういう感じ?😆」「自分なら書かないかな〜😆」「言語のチェックならアサーションとかでやる方がシンプルになりそうですし☺️」

参考: ruby/spec: The Ruby Spec Suite aka ruby/spec
参考: ruby/mspec: RSpec-like test runner for the Ruby Spec Suite

「なおRSpecも3.9がリリースされたそうです」「お、システムspecのジェネレータができた❤️」「今までなかったんですね?」「まあジェネレータがなかったというだけで、ディレクトリは前からありますし」「type: :systemで指定するのか〜」

testrocket: インラインでテストを書きたい(Ruby Weeklyより)

# 同リポジトリより
require 'testrocket'
using TestRocket

# BASIC USAGE
# +-> { block that should succeed }
# --> { block that should fail }

+-> { Die.new(2) }
--> { raise }
+-> { 2 + 2 == 4 }

# These two tests will deliberately fail
+-> { raise }
--> { true }

# A 'pending' test
~-> { "this is a pending test" }

# A description
!-> { "use this for descriptive output and to separate your test parts" }

つっつきボイス:「テストを本編コードにインラインで書きたいそうです」「スーパーシンプルであると😆」

「むむ、こういう書き方をする言語って他にもあった気がする!」「見覚えありますね🤔」「オプションつけて実行するとテストが走って、付けないと普通に動くみたいなの、あった」「何だったかな〜?」

「こういうのをうまく設計すれば、APIドキュメントとしても成立しないかなって思ったり」「いや〜邪魔😆」「邪魔😆」「そういう方向よりも、JetBrainsのIDEみたいにコードからテストコードに即ジャンプできるとかマウスオーバーでテストコードが見えるみたいな方がうれしい気がしますけどっ😆」「エンジニアにとってエディタの行数という貴重な有限のスペースを他に使いたくないですし😆」

「こういうインラインなアサーションを書く言語…Javaにあった!」「あ〜そうだった!」

参考: - JUnit 実践講座 - シナリオベースのテストケースの書き方

// 同記事より
public class LoginFormTest extends TestCase
{
    public void test() throws Exception
    {
        LoginForm form = new LoginForm();

        form.setUserId("user1");
        form.setPassword("password1");

        form.execute();

        assertEquals("こんにちは,ユーザ1さん!", form.getMessage());
    }
}

その他Ruby

言語・ツール

Bashヒストリーの便利ワザ


つっつきボイス:「!$は知らないな〜」「!:なんちゃらは使うこともあるかな」「!:0はコマンド自身で、!:1以降が引数になる」「知りませんでした😅」

$ !:0 !:1 !:3 !:2
tar -cvf afolder.tar afolder

!$:hは知らないな〜」「前回のコマンドの引数の親ディレクトリを取れるらしい」「挙動がよくわからないうちにこの辺を使うのはコワいかも😅」

$ tar -cvf system.tar /etc/system
 tar: /etc/system: Cannot stat: No such file or directory
 tar: Error exit delayed from previous errors.

$ cd !$:h
cd /etc

「コマンド履歴を当てにしすぎてると、ある日履歴が吹っ飛んで悲しい思いをしたりしますよね😅」「rsyncとかであるある😅」

その他

awesome-for-beginners: 初心者に優しいオープンソースプロジェクトリスト


つっつきボイス:「Gobyの@st0012さんがここにGobyも登録したいと言ってて知りました: 初心者にとって敷居が低いプロジェクトの言語別リストだそうです」「Hanamiも入ってる🌸」「優しいというか比較的開かれたコミュニティという感じでしょうね☺️」

「Rubyのohai↓もリストにありますね」「ohaiって何でしょう?」「CPUとかメモリみたいな実行環境を詳しくプロファイリングするヤツですね」「へ〜!😳」「ChefとかAnsibleで、たとえばメモリの何割をconfigに使うかとか、Railsのワーカー数とかを動的に指定するときなんかに使えます😎」

参考: About Ohai — Chef Docs

{
  "filesystem" => {
    "/dev/disk0s2" => {
      "size" => "10mb"
    },
    "map - autohome" => {
      "size" => "10mb"
    }
  },
  "network" => {
    "interfaces" => {
      "eth0" => {...},
      "eth1" => {...},
    }
  }
}

「Ohaiにとっては、新しい環境が出てきたときにそれを足してくれるだけでありがたいので、コミットしやすいんでしょうね☺️」「なるほど!」「だからすご〜くマイナーなディストリとかの環境を追加すればそれだけで喜んでもらえますよきっと😋」

「あれ?Gobyもリストに入ってますけど😆」「あホントだ!、いつの間に😳」「早業😆」

クンロクモデムが100万円の時代

遠い昔に雑誌で音響カプラの写真を見たとき、何に使うのかわからなかったのを思い出しました。

参考: 音響カプラ - Wikipedia


つっつきボイス:「この辺はおっさん話ですみません😅」「カプラはさすがに知らないわ〜😆」「電話の受話器に無理やりマイクとスピーカーをはめ込んでデータ通信するという原始的なヤツです😆」

「そういえばモデムの時代にも、モデムの音を録音されるとパスワード情報を抜き取られるなんて話がありましたね🤣」「あ〜たしかに可能だ🤣」「モデムのピ〜ガガ〜って音にはデータが全部乗ってるから、録音しちゃえばパスワードも含めて復号できちゃいます☺️」「デジタルデータを音にエンコード・デコードしてるだけだから、もともとそういうものですし😆」

番外

今度はWi-Fiで


つっつきボイス:「この方面の研究は割と前からありますね☺️」「ありますね〜☺️」「そうでしたか!😳」「データソースは物珍しいけど内容はよくある感☺️」「それを実際に実装して動かしたのはスゴい💪」「恣意的な部分も相当ありそうですが😆」「研究ってそんなもんです🤣」「一般性なくても『この人かどうかさえわかればいい』とかかもしれませんね😆」


今回は以上です。

バックナンバー(2019年度第4四半期)

週刊Railsウォッチ(20191008後編)Ruby 2.7のInteger#[]でバイナリチェック、rubyzip gemは強力、13KBのJavaScriptゲームほか

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

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

Rails公式ニュース

Ruby Weekly

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

この記事の著者

hachi8833

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

hachi8833の書いた記事

夏のTechRachoフェア2019

週刊Railsウォッチ

インフラ

ActiveSupport探訪シリーズ