- 開発
週刊Railsウォッチ(20190729-1/2前編)Rails 6のリリースは近そう?、Evil MartiansのRails+Docker記事、Railsパフォーマンス測定ほか
こんにちは、hachi8833です。夏がやってまいりました。
- 各記事冒頭には⚓でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
- 「つっつきボイス」はRailsウォッチ公開前ドラフトを(鍋のように)社内有志でつっついたときの会話の再構成です👄
- 毎月第一木曜日に「公開つっつき会」を開催しています: お気軽にご応募ください
⚓週刊Railsウォッチ「公開つっつき会」第13回のお知らせ(無料)
1年目を越えた第13回目公開つっつき会は、8月1日(木)19:30〜にBPS会議スペースにて開催されます。引き続き皆さまのお気軽なご参加をお待ちしております🙇。
⚓Rails: 先週の改修(Rails公式ニュースより)
今回は公式情報からです。
だいぶサイレントにrc2リリースされたけどここで拾われんかった非互換やバグはそのまま出てしまうんでお手隙の方はご自身のgemやappでrc2問題なく動くか試して頂くのがよろしいかと思います
— Ryuta Kamizono (@kamipo) July 24, 2019
つっつきボイス:「多くの人はrc2が取れてから使いはじめてバグを踏むから😆、rc2で動かして見つけてくれないと出ちゃうよ、と」「rc2と最終リリース、ほぼほぼ変わらないですし☺️」
「この後でも取り上げますが、Rails 6が近々リリースされるかもしれないそうです」「お、そういえば7月末だか8月第一週ぐらいにリリースされるかもって聞いたし」「いよいよ出るのか〜(感無量)」「6.0の後早々に6.0.1を出さずに済むためにも、やれる人は今のうちにrc2でやってみましょう〜☺️」「社内プロジェクトでも上げられそうなものがあったらやってみますか😆」
なお、以下はつっつき後の日曜のツイートです。どうぞお大事に。
今週めちゃくそマージされまくって昨日は熱出して寝込んでたからこれからいろいろ確認せなあかんのだいぶ大変
— Ryuta Kamizono (@kamipo) July 28, 2019
「6.0の新機能といえば、Action TextにAction Mailbox、それとツァイトなんとか😆」「Zeitwerkですね」「Action Textあまり語られてない感が😆」
⚓Active Storageにファイルを追加するとhas_many_attached
の元からあったファイルを消すかどうかの振る舞いを選択可能に
期待する振る舞い:
元のファイルアップロードは保存されるべき。上の再現手順の最後のステップでは、モデルのインスタンスには元のファイルと追加アップロードしたファイルの両方が保存されるべき。
実際の振る舞い:
追加のファイルをアップロードすると元のファイルが吹っ飛び、新しいファイルしか残らない。
注意: 現在の振る舞いは機能するために必要な方法であるという議論もあるだろう。しかし現在の6.0.0rc1の振る舞いは、5.2.2.1で観察される振る舞いとは違うので、これが新たなバグを呼び込むかもしれないという気がする。
同issueより大意
5.2ではattachmentsのコレクションを代入するとコレクションに追加される。この振る舞いに依存している既存の5.2アプリを6.0にアップグレードしても壊れないようになった。
6.0以降に生成した新しいアプリでは、代入するとコレクション内の既存のattachmentsは置き換わる。既存のattachmentsを消さずにコレクションにattachmentsを新たに追加するのであれば#attach
を使うべき。
自分は6.1では古い振る舞いがdeprecateされることを期待している。
同PRより大意
# activestorage/lib/active_storage/attached/model.rb#L95
def #{name}=(attachables)
- attachment_changes["#{name}"] =
- if attachables.nil? || Array(attachables).none?
- ActiveStorage::Attached::Changes::DeleteMany.new("#{name}", self)
- else
- ActiveStorage::Attached::Changes::CreateMany.new("#{name}", self, attachables)
+ if ActiveStorage.replace_on_assign_to_many
+ attachment_changes["#{name}"] =
+ if attachables.nil? || Array(attachables).none?
+ ActiveStorage::Attached::Changes::DeleteMany.new("#{name}", self)
+ else
+ ActiveStorage::Attached::Changes::CreateMany.new("#{name}", self, attachables)
+ end
+ else
+ if !attachables.nil? || Array(attachables).any?
+ attachment_changes["#{name}"] =
+ ActiveStorage::Attached::Changes::CreateMany.new("#{name}", self, #{name}.blobs + attachables)
end
+ end
end
CODE
つっつきボイス:「もしかしてマルチプルアップロードを誰も使ってなかった?😆」「んなこたーない😆」「RedMineとかでもめっちゃ使いますし☺️」「6.0でマルチプルアップデートの振る舞いが変わるけど、このままだと5.2とかで現在の振る舞いを当てにしているコードがコケるから、それを回避するということみたいです」
「変更後の仕様の方が本来ということか: 1つのhas_manyなcollectionが対象なんだから、再アップロードしたら洗い替えするものでしょうって」「洗い替えか〜」「複数ファイルの組み合わせの完全性を保証したいというときもあるから、洗い替えするかどうかを選べるオプションは一時的にあってもいいかな」「APIとしてはbreaking changesになるから、追加でやりたい人は#attach
を使えと」「ぐぉっ、またPCがフリーズした😇」「モニタを私のに差し替えましょう」
「古い振る舞いは6.1でdeprecateしようとPRにあります」「PRもマージされてissueも閉じたからそういう流れか」「config.active_storage.replace_on_assign_to_many
という設定も追加されてますね」「false
にすれば従来の振る舞いになるという、いつもの延命措置😆」「知らずにアップグレードするとコケると😆」
その後私がRailsガイドを6.0向けに更新翻訳しているときに、アップグレードガイドで該当の記述をたまたま見つけました。Active Recordの挙動に合わせたんですね。プルリクにも目的を書いて欲しいです😢。
- Active Storageの代入の振る舞いの変更: railsguides.jp/upgrading_ruby_on_rails.md at 6e408b972e80df608e8fbf50a3ca7000c15ef620 · yasslab/railsguides.jp
Rails 6.0のデフォルト設定では、添付ファイルのコレクションへの代入は、追加ではなく既存ファイルの置き換え操作になります。これにより、Active Recordでコレクションの関連付けに代入するときの振る舞いと一貫するようになります。
アップグレードガイドのドラフトより(強調は編集部)
「ところで上のコードの末尾にあるCODE
って何かしら?🤔」「たぶんヒアドキュメントの終わり部分では?😆」「あ、そのちょっと上に開始部分があった↓😅」「そもそもメソッド名に#{name}
みたいなのが書かれてる時点でヒアドキュメントっぽいですし😆」
def has_many_attached(name, dependent: :purge_later)
generated_association_methods.class_eval <<-CODE, __FILE__, __LINE__ + 1
def #{name}
...
CODE
⚓新機能: ハッシュの条件で開始値なしのrangeをサポート
Ruby 2.7で導入予定の開始値なしrangeをいち早く取り入れたようです。
# 同PRより
Order.where(created_at: ..1.year.ago)
class Users < ApplicationRecord
scope :unruly, -> { where(karma: ...0) }
# activerecord/lib/arel/predications.rb#L37
def between(other)
if unboundable?(other.begin) == 1 || unboundable?(other.end) == -1
self.in([])
- elsif open_ended?(other.begin)
+ elsif other.begin.nil? || open_ended?(other.begin)
if other.end.nil? || open_ended?(other.end)
not_in([])
elsif other.exclude_end?
lt(other.end)
else
lteq(other.end)
end
elsif other.end.nil? || open_ended?(other.end)
gteq(other.begin)
elsif other.exclude_end?
gteq(other.begin).and(lt(other.end))
else
left = quoted_node(other.begin)
right = quoted_node(other.end)
Nodes::Between.new(self, left.and(right))
end
end
つっつきボイス:「PC再起動完了」「開始値なしのrangeって不思議感ありありだし😆」「Ruby 2.7で入るんですね」「これどういうクエリになるんだろうか?🤔」「大なり小なりとかでやるのかも?」「なんか微妙に読みづらくなりそう😅」
⚓新機能: SMSリンクを作成するsms_to
ヘルパーメソッド
<%= sms_to "15155555785", "Text me", body: "I have a question.." %>
# actionview/lib/action_view/helpers/url_helper.rb#L606
+ def sms_to(phone_number, name = nil, html_options = {}, &block)
+ html_options, name = name, nil if block_given?
+ html_options = (html_options || {}).stringify_keys
+
+ extras = %w{ body }.map! { |item|
+ option = html_options.delete(item).presence || next
+ "#{item.dasherize}=#{ERB::Util.url_encode(option)}"
+ }.compact
+ extras = extras.empty? ? "" : "?&" + extras.join("&")
+
+ encoded_phone_number = ERB::Util.url_encode(phone_number)
+ html_options["href"] = "sms:#{encoded_phone_number};#{extras}"
+
+ content_tag("a", name || phone_number, html_options, &block)
+ end
つっつきボイス:「リンクを叩くとSMSメッセージ画面↓がPC/Android/iOSのどれでも表示されるそうです」「sms:
なんちゃらのショートハンドなのね」「hrefにsms:
って書けるって知らなかったし😆」
<a href="sms:5155555785;?body=Hello%20Jim%20I%20have%20a%20question%20about%20your%20product">Text me</a>
⚓新機能: ActiveRecord::QueryAborted
スーパークラスを追加
あらゆるタイムアウトを
rescue
するには(ただしそれ以外のクエリ例外はrescue
しないとする)、rescue ActiveRecord::QueryCancelled
とActiveRecord::StatementTimeout
とActiveRecord::AdapterTimeout
を行わなければならない。これでは、どれかひとつ足し忘れて欲しいものをrescue
できなくなりがち。
そこで、すべてのタイムアウトエラーを簡単にrescue ActiveRecord::QueryAborted
できるよう、スーパークラスを1つ導入してみたいと思う。
同PRより大意
# activerecord/lib/active_record/errors.rb#L357
+ class QueryAborted < StatementInvalid
+ end
+
# LockWaitTimeout will be raised when lock wait timeout exceeded.
class LockWaitTimeout < StatementInvalid
end
# StatementTimeout will be raised when statement timeout exceeded.
- class StatementTimeout < StatementInvalid
+ class StatementTimeout < QueryAborted
end
# QueryCanceled will be raised when canceling statement due to user request.
- class QueryCanceled < StatementInvalid
+ class QueryCanceled < QueryAborted
end
# AdapterTimeout will be raised when database clients times out while waiting from the server.
- class AdapterTimeout < StatementInvalid
+ class AdapterTimeout < QueryAborted
end
つっつきボイス:「クエリのタイムアウトをrescueするときにQueryAborted
一発で囲んで集約したいということか」「クエリをパースするタイミングで発生するエラーを同一視したいというか」「クエリを投げたときに失敗する可能性のあるエラーをすべて1個のスーパークラスにしたというか」
「StatementTimeout
って見た目だけで推測すると、SELECTを打ってから返ってくるまでの時間が長すぎた場合にRDBMSの何かのパラメータに基づいてタイムアウトする、とかかな〜😆」「それっぽいかも☺️」
「QueryCanceled
はどういうタイミングで出るのかな?🤔」「たぶんですが、トランザクション分離レベルで待つとか?」「と思ったらコードの上に説明書いてあった🤣」「QueryCanceled
はユーザー側でキャンセルした場合か」「BEGIN TRANSACTIONとかの中でキャンセルできた気がするからそういう場合なのか、それともぽすぐれがマルチスレッドクエリを使えた覚えがあるからそっちかな?とも思うけど、とりあえず推測ですし😆」
「とにかくこういうタイムアウトたちを一回で取れるようにしたいと😆」「こういうの今後も増えてきそうですし😆」「その基盤はできたと☺️」
「こういう処理って、こうやってスーパークラスを作ってやる場合もあれば、query aborted typesみたいな感じで配列に入れてincludes?
で評価するやり方もあったりしますよね」「rescueするときはスーパークラスの方がやりやすそうかな〜☺️」
⚓新機能: ジェネレーターのskip-collision-check
オプション
y-yagiさんのPRです。
Rails 5.2までは同じ名前のジェネレータを
destroy
せずに複数回実行できたが、Rails 6.0とZeitwerkではできない。クラス名のコリジョンチェックでエラーになる。
このチェックではconst_defined?
↓を使っているが、これはオートロードオブジェクトも定義されていることが前提になっている。
この部分はRails 5.2まで機能していなかったが、Zeitwerkならアプリケーションのコードを正しくチェックできそうに見える。
ただし、たとえば間違えた属性名を修正するためにジェネレータを再実行する(その場合事前にdestroy
しておく必要がある)ときに少々不便。
PRはこの点を解消するためにコリジョンチェックをスキップするオプションを追加する。このオプションを使えばRails 5.2までと同様ファイルを上書きできるようになる。
同PRより大意
# railties/lib/rails/generators/base.rb#L252
def class_collisions(*class_names)
return unless behavior == :invoke
+ return if options.skip_collision_check?
class_names.flatten.each do |class_name|
class_name = class_name.to_s
next if class_name.strip.empty?
# Split the class from its module nesting
nesting = class_name.split("::")
last_name = nesting.pop
last = extract_last_module(nesting)
if last && last.const_defined?(last_name.camelize, false)
raise Error, "The name '#{class_name}' is either already used in your application " \
- "or reserved by Ruby on Rails. Please choose an alternative and run " \
- "this generator again."
+ "or reserved by Ruby on Rails. Please choose an alternative or use --skip-collision-check " \
+ "to skip this check and run this generator again."
end
end
end
参考: Class: Module (Ruby 2.6.3)
つっつきボイス:「これはどのジェネレータ?」「rails g
のジェネレータか」「multiple timesはジェネレータを複数回実行するってことなのね」「ぱっと見同時実行かと思った😆」「ジェネレータでフィールド名間違えたりしたときにbashの履歴から修正して再実行するときとかなんでしょうね」「destroy
しなくてもやれるようにしたと」
「rails g
って自分はマイグレーションのときぐらいしか使わないけど😆、マイグレーションを再実行したらどうなるんだろう?」「マイグレーションファイルにはタイムスタンプが付くからマイグレーションは再実行してもかぶらなさそうだけど🤔」「でも同じクラスがあったらそれこそコリジョンしそうですし😆」「上のコードのメッセージにこう書いてある↓ぐらいだから、今はコリジョンするようになってるんですね☺️」
The name '#{class_name}' either already used in your application or reserved by Ruby on Rails. Please choose an alternative and run this generator again.
「ということはこのskip-collision-check
はマイグレーションでも使えるということかな?」「ということでしょうね」「Railsチュートリアルとかだとワンライナーでマイグレーションを作れるのは便利そうですけど☺️」
⚓issue: Rails 6 rc2のマルチプルDBでテストが通らない
rails db:create
rails db:migrate
rails test
つっつきボイス:「こちらはPRではなくissueなんですが、rc2が出たときは空になっていたRC2のマイルストーンを見に行ったら、これが加わっていました(その後3つに増えています)」「rc1とrc2って相当差が出ましたからね〜」「マルチDBの設定が必要なのか」「これはまさにrc2でテストやってくれてありがとうというissueですね☺️」「再現用のリポジトリとかも作ってくれてるとか有能」「kamipoさんが望んでいるのはまさにこれ」「私も試しに取り急ぎローカルで再現しようとしたら、なぜかポスグレのgemが自分の環境でつっかえたのでそこどまりです😅」
なお、つっつきの後で伸びたスレで、#36439でのSchemaMigration
の移動が影響しているらしいという書き込みがありました。
⚓Rails
⚓Railsのどこで時間がかかっているか(Hacklinesより)
#同記事より抜粋
==================================
Mode: cpu(1000)
Samples: 4293 (0.00% miss rate)
GC: 254 (5.92%)
==================================
SAMPLES (pct) FRAME
206 (4.8%) ActiveRecord::Attribute#initialize
189 (4.4%) ActiveRecord::LazyAttributeHash#[]
122 (2.8%) block (4 levels) in class_attribute
98 (2.3%) ActiveModel::Serializer::Associations::Config#option
91 (2.1%) block (2 levels) in class_attribute
90 (2.1%) ActiveSupport::PerThreadRegistry#instance
85 (2.0%) ThreadSafe::NonConcurrentCacheBackend#[]
79 (1.8%) String#to_json_with_active_support_encoder
つっつきボイス:「パフォーマンス系でおなじみNoah Gibbsさんの記事です」「まずはプロファイリングをinstrumentationでやるか、サンプリングでやるか」
「シングルスレッドとマルチスレッドでそれぞれ測定してますね」「Noah Gibbsさんのこの記事は、どういう戦略でいくかを示してから実際に測定して切り分けていくという順序で進んでいくのがいいですね〜❤️」「おぉ〜」「『推測するな。計測せよ。』を実践してる人☺️」
参考: UNIX哲学 - Wikipedia -- 「推測するな。計測せよ。」の出典
「結論↓は普通っぽい😆」「でも測定で裏付けたという」「数値でちゃんと出したのが重要☺️」
- Railsをきちんと設定したとしても、Rails CRUDアプリの時間はDBクエリやActive Recordやシリアライズにかなり食われる
- GCはRuby 1.9よりかなりよくなっているが、それでも少なからぬ時間を食われてる → ごみオブジェクトを減らせ
- DBのオーバーヘッドに加えて、Active Recordもかなりオーバーヘッドがある → Sequelなどのオルタナティブを検討
- StackProfは使いやすくていいヤツなのでRubyアプリでやってみる価値あり
「Sequelか〜😅」「StackProfってNoah Gibbsさんが作ったような気がしてたけど違った😅」「@tmm1さんか」「tackProfのcontributor見ると@tenderloveさんとかいろんな人がやってるし😳」「そういえばCSVが遅遅だったときに StackProf使ったことあったわ: 今ググったら検索結果で自分がこのリポジトリをクリックした跡残ってるし😆」
参考: tmm1/stackprof: a sampling call-stack profiler for ruby 2.1+
⚓LefthookとCrystalballとGitのマジックで楽に開発しよう(Ruby Weeklyより)
- 元記事: Lefthook, Crystalball, and git magic for smooth development experience - DEV Community 👩💻👨💻
- リポジトリ: Arkweid/lefthook: Git hooks manager -- Gitフックを管理
- リポジトリ: toptal/crystalball: Regression Test Selection library for your RSpec test suite -- リグレッションテストのライブラリ
おなじみEvil Martiansの記事です。
つっつきボイス:「crystalballはRubyKaigiにも登場してましたね→」
「それとLefthook」「お〜Gitフックマネージャか」「ボクシングの左フックにかけてるんでしょうね😆」「Overcommit↓と似たようなものをEvil Martiansが作ったと」「しかもGo言語で」「LefthookでフックをかけてCrystalballを動かすみたいな」
「Crystalballって何でしたっけ?」「影響しそうな部分だけテストするみたいなgem」「いわゆる占いの水晶玉🔮」
「こういう組み合わせで速くなるといいですね〜: RSpecがGitのフックで動くともうストレスでしかないし😭」「みんなローカルでテストしてからにしてねと言いたいけど、ローカルで回しても時間かかりますし🕗」「回してる間に余裕でメシ食えるし😆」「昔のLinuxカーネルとかX11とか、帰る前にコンパイルを走らせたりしましたね〜😇」「そして翌日も終わってなかったり😆」「この記事翻訳したいです😋」
⚓Evil MartiansのDocker記事
つっつきボイス:「Evil MartiansがRails+Docker記事も出してますね」「Evil Martiansはこうやったと」「たしかRailsConfでRailsアップグレードをテラフォーミングになぞらえた話をしたときのサイドストーリーということね」
「先週のDocker記事よりはイケてるかな?」「Aptfile
って?」「これをcat
して出てきたリストをapt-get
するという😆」「あ〜なるほどっ」「大文字で始まってるから何かのパッケージかと思ったら、それをやってるだけ😆」「わかる〜😍、こういうのってちょいちょい更新したくなるし」
# 同記事より
# We use an external Aptfile for that, stay tuned
COPY .dockerdev/Aptfile /tmp/Aptfile
RUN apt-get update -qq && DEBIAN_FRONTEND=noninteractive apt-get -yq dist-upgrade && \
DEBIAN_FRONTEND=noninteractive apt-get install -yq --no-install-recommends \
build-essential \
postgresql-client-$PG_MAJOR \
nodejs \
yarn=$YARN_VERSION-1 \
$(cat /tmp/Aptfile | xargs) && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && \
truncate -s 0 /var/log/*log
「こちらのdocker-composeはちゃんとcached
やってますね😋、と思ったら記事の中でもcached
説明してるし」
volumes:
- .:/app:cached
- bundle:/bundle
- rails_cache:/app/tmp/cache
- node_modules:/app/node_modules
- packs:/app/public/packs
- .dockerdev/.psqlrc:/root/.psqlrc:ro
「ぽすぐれのメジャーバージョンをアップグレードするなんてのはめったに起きないから最初にやっとくと」「NodeやYarnもそんなにしょっちゅう変わらないだろうし」「その次のbuild-essential、新しいのを使いたいから入れてるんじゃないかなと」「お、node_modulesをボリュームにするのか」
ARG RUBY_VERSION
# See explanation below
FROM ruby:$RUBY_VERSION
ARG PG_MAJOR
ARG NODE_MAJOR
ARG BUNDLER_VERSION
ARG YARN_VERSION
# Add PostgreSQL to sources list
RUN curl -sSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - \
&& echo 'deb http://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main' $PG_MAJOR > /etc/apt/sources.list.d/pgdg.list
# Add NodeJS to sources list
RUN curl -sL https://deb.nodesource.com/setup_$NODE_MAJOR.x | bash -
# Add Yarn to the sources list
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
&& echo 'deb http://dl.yarnpkg.com/debian/ stable main' > /etc/apt/sources.list.d/yarn.list
# Install dependencies
# We use an external Aptfile for that, stay tuned
COPY .dockerdev/Aptfile /tmp/Aptfile
RUN apt-get update -qq && DEBIAN_FRONTEND=noninteractive apt-get -yq dist-upgrade && \
DEBIAN_FRONTEND=noninteractive apt-get install -yq --no-install-recommends \
build-essential \
postgresql-client-$PG_MAJOR \
nodejs \
yarn=$YARN_VERSION-1 \
$(cat /tmp/Aptfile | xargs) && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && \
truncate -s 0 /var/log/*log
「記事の後半でコンフィグをステップバイステップでめっちゃ丁寧に説明してくれてるし!」「エライ!🎉」「超エライ👍」「これも翻訳したいです😋」
⚓docker-composeで便利そうなdip
「記事の最後にdipというツールが紹介されてますね: docker-composeで設定したアプリをCLIでインタラクティブに操作するみたいです」
- リポジトリ: bibendi/dip: CLI gives the "native" interaction with applications configured with Docker Compose
「どういうつくりなのかな?」「docker-composeを利用したときに、docker-compose run
で使いたいものをgulp build
みたいにまとめられるんじゃないかしら: 以下のdip.ymlを見た感じではそれっぽいし↓」「ははぁ〜」
version: '2'
environment:
RAILS_ENV: development
compose:
files:
- docker-compose.yml
interaction:
bash:
service: backend
command: /bin/bash
compose_run_options: [no-deps]
bundle:
service: backend
command: bundle
compose_run_options: [no-deps]
rake:
service: backend
command: bundle exec rake
rails:
service: backend
command: bundle exec rails
subcommands:
s:
service: rails
compose_run_options: [service-ports]
yarn:
service: backend
command: yarn
compose_run_options: [no-deps]
rspec:
service: backend
environment:
RAILS_ENV: test
command: bundle exec rspec
rubocop:
service: backend
command: bundle exec rubocop
compose_run_options: [no-deps]
psql:
service: postgres
command: psql -h postgres -U postgres -d example_app_dev
'redis-cli':
service: redis
command: redis-cli -h redis
provision:
- dip compose down --volumes
- dip compose up -d postgres redis
- dip yarn install
- dip bash -c ./bin/setup
「interactionの下にbashとかbundleとかrailsとかyarnとかrspecとか書いてあるから、コマンド実行した後にいちいちRUN
で作ったりしなくてもdip run なんちゃら
でやれるとかそういう感じかなと🤔」「ちゃんと読まないとわからないけど何だかよさそう😋」
「docker-composeコマンドで延々入力したくない人向けかも」「たしかにdocker-composeってコマンド名自体が長いですよね😆」「docあたりでTab補完してもdockerで止まっちゃうし😆」
# 同リポジトリより
dip run rails c
dip run rake db:migrate
「dip ssh up
とかdip nginx up
なんてのもできるみたいですし」「dip ssh up
ってまさにコンテナにsshするときのショートハンドか」「docker-compose.ymlにこんなふうに↓書けばこのショートハンドが使えるのね😳」
services:
web:
environment:
- SSH_AUTH_SOCK=/ssh/auth/sock
volumes:
- ssh-data:/ssh:ro
volumes:
ssh-data:
external:
name: ssh_data
「dip nginx up
の設定もnetworksの下にexternal:
を指定してるから、別のdocker-composeからアクセスできるんだろうな」「nginxプロキシを差し込めると」「frontendの方でこれに合わせておいてくれればnginxをそっちに向けるよ、と」「dip dns up
なんてのもできるし😍」「これ欲しかった人いるんじゃ?😆」
version: '2'
services:
foo-web:
image: company/foo_image
environment:
- VIRTUAL_HOST=*.bar-app.docker
- VIRTUAL_PATH=/
networks:
- default
- frontend
dns: $DIP_DNS
networks:
frontend:
external:
name: frontend
「たしかにdocker-composeで一度作っちゃった後でsshで入ろうとするのも閉じるのも面倒くさかったりするけど、こういう感じで一種の『付け外しできるバックドア的なツール』として使えるのかなと」「全部の機能を残らず使うかというと疑問ですけど😆」「知ってれば便利に使えそう❤️」「sshとDNSとnginxプロキシ、どれもやれたらうれしいヤツだし😋」「後でちゃんと見てみようかな☺️」
⚓pg_search: PostgreSQLの全文検索をActive Recordで(Ruby Weeklyより)
- リポジトリ: Casecommons/pg_search: pg_search builds ActiveあRecord named scopes that take advantage of PostgreSQL’s full text search
- 関連記事: pg_search: How I Learned to Stop Worrying and Love PostgreSQL full-text search -- 2011年の記事です
# 同リポジトリより
class AntipatternExample
include PgSearch::Model
multisearchable against: [:contents],
if: :published?
def published?
published_at < Time.now
end
end
problematic_record = AntipatternExample.create!(
contents: "Using :if with a timestamp",
published_at: 10.minutes.from_now
)
problematic_record.published? # => false
PgSearch.multisearch("timestamp") # => No results
sleep 20.minutes
problematic_record.published? # => true
PgSearch.multisearch("timestamp") # => No results
problematic_record.save!
problematic_record.published? # => true
PgSearch.multisearch("timestamp") # => Includes problematic_record
casebookというニューヨークの会社が作っているgemです。
つっつきボイス:「pg_searchは前からあるgemで、ずっと前にウォッチでちょっとだけ取り上げたことがありました」「ぽすぐれのフルテキストサーチですね☺️」「名前は聞いたことありますし☺️」「multisearchable
とな😆」「こういう感じの名前って昔のgemによくありましたね」「最近流行りませんけど😆」
# 同リポジトリより
class EpicPoem < ActiveRecord::Base
include PgSearch::Model
multisearchable against: [:title, :author]
end
class Flower < ActiveRecord::Base
include PgSearch::Model
multisearchable against: :color
end
「pg_searchはPostgreSQLに何か拡張とか入れる必要あるのかな?」「READMEにはPostgreSQLの全文検索機能を利用すると書いてあるから、なしでもできそうですね」
「Ransackとかとは違うヤツでしょうか?」「全然違いますね😆」「ransackは全文検索とはアルゴリズムがまるで違いますし」「そうでしたか😅」「言ってみればRansackは、Arelを組み立てやすくするためのgemですから」「検索条件を組み立てやすくするものなんですね」「もしかするとpg_searchもRansackと併用できるかもしれないけど」「わかんないけどできそう😆」
⚓better_errorsを高速化
とても短い記事です。
つっつきボイス:「better_errorsが遅いとかあまり思ったことないけど😆」「でっかいオブジェクトを巻き込んじゃうと遅くなったりするみたいですね」「そんなこともあるのかと😆」
「あ〜なるほど、inspectがすごくでっかくなっちゃうときか」「そういうときは早々と諦めると😆」「if inspected.size > 20_000
のときに諦めるのね😆」
⚓その他Rails
- 元記事: Goodbye ActiveRecord! - Inside Aircall - Medium -- Active RecordをやめてROMにした理由(Ruby Weeklyより)
つっつきボイス:「エントリ増やしすぎないようにと思いつつ貼りました😅」「Active RecordをやめてROM(Ruby Object Mapper)にしてみたと」「まあたしかにActive Recordはヤバいくらい多機能ですけどね☺️」
- サイト: ROM
⚓勉強会・書籍
- 勉強会: 【Roppongi.rb特別編】Rails 6リリースするかも?Party at Speee - connpass
- 勉強会: Meguro.rb#29 2019/7/31(Wed.) at Wantedly, Inc.|IT勉強会ならTECH PLAY[テックプレイ]
- 書籍: イケてないアプリケーションで試すセキュリティホール Ruby on Rails版 - ken1flan - BOOTH
つっつきボイス:「『Rails 6リリースするかも?Party at Speee?』の特別ゲストのリストを見ると、先日の銀座Rails#11↓のときにいた人が全員いるというあたりで既視感が蘇ってきました🤣」「そうそう、全員いましたし🤣」「へぇ〜!」
「Meguro.rbはSlackを開設してるので取りあえず入ってみました😋」
「3つ目の書籍は、これも銀座Rails#11で発表していたken1flanさんが出してる本だそうで、新人教育でセキュリティホールの空いたアプリを触ってもらって実地に学ぶというのをやってるそうです」「『ちゃんと作らないとこうなるよ』と😆」「セキュリティはこうやって実際に見せるとわかりやすいですよね☺️」
前編は以上です。
おたより発掘
ふむふむ 有難い情報満載ですね / “週刊Railsウォッチ(20190729-1/2前編)Rails 6のリリースは近そう?、Evil MartiansのRails+Docker記事、Railsパフォーマンス測定ほか” https://t.co/Lvw9H3zNYx
— FUKUI Osamu (@iR3) August 2, 2019
バックナンバー(2019年度第3四半期)
週刊Railsウォッチ(20190722-1/2前編)Rails 6エラー画面の改良点、Dateを四捨五入できるtime_calc、Rackミドルウェアのデザインパターンほか
- 20190717-2/2後編 NFSのよさとは、Linuxカーネル5.2リリース、Puppeteerでメモリリーク検出ほか
- 20190709-2/2後編 strong_password v0.0.7がハイジャックされていた、TerraformとCloudFormation、CSSの設計ミスリストほか
- 20190708-1/2前編 ActiveRecord::FixtureSetがめちゃ強くなってた、MacだとRubyが遅い理由、Puma 4登場ほか
- 20190701 RMagickのメモリ使用量が劇的に改善、インスタンス変数の定義順で速度が変わる?、GitLab CIランナーをローカルで回すほか
今週の主なニュースソース
ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSなど)です。