- Ruby / Rails関連
週刊Railsウォッチ(20210125前編)Railsリポジトリのデフォルトブランチがmainに変更、Rails 6.1はMySQLのENUM型に対応済みほか
こんにちは、hachi8833です。
- 各記事冒頭には⚓でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
- 「つっつきボイス」はRailsウォッチ公開前ドラフトを(鍋のように)社内有志でつっついたときの会話の再構成です👄
- お気づきの点がありましたら@hachi8833までメンションをいただければ確認・対応いたします🙇
TechRachoではRubyやRailsの最新情報などの記事を平日に公開しています。TechRacho記事をいち早くお読みになりたい方はTwitterにて@techrachoのフォローをお願いします。また、タグやカテゴリごとにRSSフィードを購読することもできます(例:週刊Railsウォッチタグ)
⚓Rails: 先週の改修(Rails公式ニュースより)
今回は以下のコミットリストを中心に見繕いました。
⚓ type_for_attribute
周りを修正
マージされたプルリク#39929によって、
cast_type
(:encrypted
)でprev_decorator
(store
の中のserialize
)を用いると#41138のリグレッション(注: 修正したバグが再発すること)が発生した。複数のデコレーション(元の属性の
store
の:encrypted
)はこれまで全くサポートされていなかったので、これまで動いていたのは偶然に過ぎないが、サブクラスの型の省略を許すことと引き換えに複数のデコレーション機能が動かなくなるようにはしたくない。個人的には、たとえ以下のようにサブクラス側で型を省略可能だとしても、開発者がサブクラス側で型を省略することはおすすめしたくない。
# 同PRより
# app/models/post.rb
class Post < ActiveRecord::Base
attribute :x, :integer
end
# app/models/special_post.rb
class SpecialPost < Post
# :integerは省略可能だが、明快さが落ちる
attribute :x, default: 42
# :integerは以下のように省略なしで記述することを推奨
attribute :x, :integer, default: 42
end
コメント94ba417#r41923157の視点もこれに似ている。
修正されたissue: #41138
同PRより大意
参考: リグレッション(りぐれっしょん) - ITmedia エンタープライズ
つっつきボイス:「そういえばRailsのActiveRecord::Attributes
にはこういう機能がありますね(自分はこの書き方はあまりしないんですが): 現在は上のように、元のクラスを継承した後でActiveRecord::Attributes
を上書きすると、元のattributeのinteger
が上書きされて消えることになる」「おぉ」「上のコードの末尾にあるこの:interger
は、実際には省略しないで明示的に書くべきという指摘もされてますね」
「issue #41138の方が見やすいかな↓: 元のコード(上)にあったものが、継承したコード(下)で上書きされている」「なるほど!」「プルリクはこのリグレッションの修正ということですね」「修正に伴って#39929も取り消されていました」
# issue #41138より
class Cache < ApplicationRecord
store :data
encrypts :data
end
# issue #41138より
def encrypts(name)
attribute name, :encrypted, subtype: type_for_attribute(name)
end
「元のクラスの他のattributeは自分が使わないとしても、store
やencrypted
あたりは使うこともあるでしょうから、知らないうちにこの問題を踏むということはありそう」「名前が重複するから、これまで上書きされていたのも無理はないか」「内部の処理が見えないと、この問題を踏んでも何が起こったのか見当がなかなかつかなくて厄介でしょうね」
⚓ timeのunknown type errorを定義時にraiseするようにした
つっつきボイス:「これもActiveRecord::Attributes
の改修かな: unknown type errorをランタイム時ではなく定義時に出力するように変わってますね」
# activerecord/lib/active_record/attributes.rb#L215
when Symbol
- type = cast_type
- cast_type = -> _ { Type.lookup(type, **options, adapter: Type.adapter_name_from(self)) }
+ cast_type = Type.lookup(cast_type, **options, adapter: Type.adapter_name_from(self))
「postgresql/datatype_test.rbのテストにも手が入っているから、PostgreSQLアダプタ関連の修正なのかな」「#41166のコメントを見ると、PostgreSQLアダプタでの場合分けが必要だったみたい」
「定義時にエラーとわかったらその時点でエラーにしようよということですね」「検知できるエラーは早いタイミングで出すべきというのはもっともですね」
⚓ 高速化: empty?
をlength == 0
に変更
つっつきボイス:「こちらは高速化のプルリクです」「条件のassociations.nil?
を冒頭に移動したのと、records.empty?
をrecords.length == 0
に変えたのと、2つの変更が行われてますね↓」「あ、タイトルの変更以外にもうひとつ変更があったのか」「associations.nil?
の方が処理が速いのかもしれない」
# activerecord/lib/active_record/associations/preloader.rb#L100
def call
- return [] if records.empty? || associations.nil?
+ return [] if associations.nil? || records.length == 0
build_preloaders
end
「改修後は1.3倍ほど速くなったようです↓」「そういえばRubyの書き方としては== 0
より.empty?
の方がRubyらしいとよく言われますね」「== 0
にするとメソッド呼び出しを行わなくなる分速くなるのかな?」「ともあれ、この測定結果だけでは、== 0
への変更とassociations.nil?
の移動のどちらがどれだけ効いているかはわからないですね」「たしかに」
before:
Warming up --------------------------------------
prefill associations 252.000 i/100ms
Calculating -------------------------------------
prefill associations 2.549k (± 1.4%) i/s - 12.852k in 5.043288s
After:
Warming up --------------------------------------
prefill associations 335.000 i/100ms
Calculating -------------------------------------
prefill associations 3.361k (± 0.5%) i/s - 17.085k in 5.082847s
⚓ rails new
のGitデフォルトブランチ指定オプションを--main
に変更
つっつきボイス:「お、ついにrails new
するときのGitデフォルトブランチ名指定オプションが--master
から--main
に変わったのか」「はい、とうとう」「今はいろんなところでGitのデフォルトブランチ名をmain
にするのが世の中の流れですよね」「--no-master
も--no-main
に変わってる」
参考: 新しいGitHubリポジトリではmainブランチがデフォルトに
なお昨年にも同様のPRが上がっていたのを見つけましたが、こちらはopenのままです↓。
Railsまでmainブランチになるのかhttps://t.co/LeTgq41bck
— 神速 (@sinsoku_listy) September 22, 2020
🔗 Railsリポジトリのmaster
ブランチもmain
に変更された
- commit: Rename master to main in all code references · rails/rails@077c66d
- PR: [ci skip] Update Guides to refer to main branch by bencgreenberg · Pull Request #41142 · rails/rails
「上の--main
オプションの他にこの変更も行われました」「--main
なしのrails new
でもmain
ブランチができる...のかと思ったら、RailsフレームワークそのもののGitHubリポジトリまでデフォルトブランチがmain
ブランチに変わったのか!」「はい、『先週の改修』用に今週のコミットリストを取ろうとしたらいつものURLが無効になっていたことで気が付きました↓」
たしかにmainできてますね。この変更トラックしているissueご存じでしたら教えてください。https://t.co/ZysPIwL3Wj はrails new したときのブランチ名の変更のようなのでちょっと違うかなとおもってます。
— Yasuo Honda (@yahonda) January 15, 2021
「ついにRails本体までmain
に変わるのかー」「RailsのCIもいろいろ変えないといけなくなるんでしょうか?」「Rails本体のmaster
が急に消えるとえらいことになりそうなので、さすがにしばらくはmaster
とmain
が共存しそうな気がしますけどね(調べる): ...本当にmaster
ブランチない↓」
「もしかするとmaster
がGitHubのプルダウンにないだけで、master
ブランチそのものは取れるんじゃないかな?: やっぱりなかった↓」「完全にmain
に移行しちゃったんですね...」
「普通はあまりしないと思いますが、自分たちのCIでGitHubのrails/railsリポジトリを指定するときに気を利かせてmaster
ブランチまで指定していたら落ちそうではある」「あ、そうかも」
念のため自分も後でやってみましたが、やはりmaster
ブランチはありませんでした。
$ git clone https://github.com/rails/rails.git; cd rails
# 略
$ git co master
error: pathspec 'master' did not match any file(s) known to git
$ git branch -a
* main
remotes/origin/1-2-stable
remotes/origin/2-0-stable
remotes/origin/2-1-stable
remotes/origin/2-2-stable
remotes/origin/2-3-stable
remotes/origin/3-0-stable
remotes/origin/3-1-stable
remotes/origin/3-2-stable
remotes/origin/4-0-stable
remotes/origin/4-1-stable
remotes/origin/4-2-stable
remotes/origin/5-0-stable
remotes/origin/5-1-stable
remotes/origin/5-2-stable
remotes/origin/6-0-stable
remotes/origin/6-1-stable
remotes/origin/HEAD -> origin/main
remotes/origin/activemodel-multiparam-attrs
remotes/origin/add-github-actions-to-rails
remotes/origin/add-spaces-integration-test
remotes/origin/add_autoload_paths_to_load_path
remotes/origin/backport-30638
remotes/origin/bump-z
remotes/origin/conductor6
remotes/origin/ditch-premature-optimization-for-collection-cache-keys
remotes/origin/do-no-shallow-name-errors
remotes/origin/fix-array-builder-wheres
remotes/origin/fix-as-with-api-apps
remotes/origin/fix-build
remotes/origin/fix-duration-modulo
remotes/origin/fix-find-root-on-ruby-2-2
remotes/origin/fix-nil-params-in-ap
remotes/origin/fixtures-refactor
remotes/origin/freeze-configuration_hash
remotes/origin/fxn/docker
remotes/origin/fxn/load-paths-per-environment
remotes/origin/issue-33155
remotes/origin/json-visitor
remotes/origin/main
remotes/origin/matthewd/inotify
remotes/origin/modernize-scaffold
remotes/origin/new-autoloading-guide
remotes/origin/no-html-fallback
remotes/origin/postgresql_type_map_lookup_fix
remotes/origin/proxy-pg-result
remotes/origin/railties-split
remotes/origin/record-timezone-when-writing-from-user
remotes/origin/remove-json-tests
remotes/origin/remove-qc-ivar
remotes/origin/settings-file
remotes/origin/test-remove-marshal-support-from-schema-cache
remotes/origin/tzinfo2
remotes/origin/use-any-bundler
remotes/origin/verify-release
remotes/origin/ಠ_ಠ
⚓ closed: 'Directly inheriting'メッセージを修正
つっつきボイス:「これはclosedですね?」「マージされてないプルリクですが、気になったので拾ってみました」
「プルリクのコメントを読むとclass #{subclass} < ActiveRecord::Migration[4.2]
の4.2
は、元々Rails 4.2以前の仕様でバージョン番号なしで実装されていたものに対するエラーメッセージなんですが、Rails 4.2以前の仕様で書かれたものを最新のmigaration number(最新では6.1)に書き換えて使ってしまうのは、前方互換が無くなった機能などを踏むリスクがより高いので適切ではないだろうということのようですね」「あ、そういうことでしたか!」
# activerecord/lib/active_record/migration.rb#L556
def self.inherited(subclass) #:nodoc:
super
if subclass.superclass == Migration
+ major = ActiveRecord::VERSION::MAJOR
+ minor = ActiveRecord::VERSION::MINOR
raise StandardError, "Directly inheriting from ActiveRecord::Migration is not supported. " \
- "Please specify the Rails release the migration was written for:\n" \
+ "Please specify the Active Record release the migration was written for:\n" \
"\n" \
- " class #{subclass} < ActiveRecord::Migration[4.2]"
+ " class #{subclass} < ActiveRecord::Migration[#{major}.#{minor}]"
⚓Rails
⚓ Rails 6.1はMySQLのENUM型に対応済み
じつはRails 6.1ではMySQLのENUM型には対応している😎https://t.co/7A2uKxRifvhttps://t.co/hReAi2wa2U
— Ryuta Kamizono (@kamipo) January 21, 2021
つっつきボイス:「BPSの社内Slackに貼っていただいた@kamipoさんのツイートです」「そうそう、MySQLについてはいち早くRailsが6.1でEnumに対応しているということでしたね」
「先週のウォッチ(ウォッチ20210120)でRailsとPostgreSQLのENUMサポートについての話になったときに、RailsがデータベースのENUM型に対応していた話を以前もしていたような気がして仕方がなかったんですが、あれはこのMySQLのENUM型をサポートしたときの話だったのかも」「私も思い出せませんでした😅」
このコミットは昨年7月にマージされていました↓。
enum
とset
は:string
として型キャストされるが、現時点の:string
型はスキーマダンプでの再利用方法が正しくない。
あるカラムのキャスト型は常にsql_type
と同じとは限らないので、このプルリクではenum
とset
のスキーマダンプが(type
ではなく)sql_type
を正しく使うよう修正した。
同PRより大意
「この追加機能はマイグレーションに多少影響しそう」「DBMS依存の部分も結構ありそうな気がしました」
⚓ 最近のRailsテストに関するアンケート(Ruby Weeklyより)
つっつきボイス:「TechRacho翻訳記事でもお世話になっているarkencyによるツイートまとめ記事です」「記事に貼られているツイートはこれね↓」「RSpec派は8割、Minitest派は2割か」
80% favor RSpec.
Pretty much what you could expect. pic.twitter.com/nh7cBjUvUR
— Tomasz Wróbel (@tomasz_wro) January 11, 2021
「これ↓を見ると受け入れテスト(acceptance test: ここではCucumberなどによるRailsの自動テスト)を書いている人もそれなりにいるのね」「ホントだ」
What tests you mostly rely on — here comes the never-ending issue of how we name different test types.
First three follow the original Rails naming and unit tests are leading. pic.twitter.com/a2VwhdjE5y
— Tomasz Wróbel (@tomasz_wro) January 11, 2021
「今思ったんですが、ここで受け入れテストを書いていると回答している人は、昔BDD(Behavior Driven Development)が流行った頃にそのプロジェクトでCucumberやTurnipのテストが書かれたからじゃないかな」「それ、ありそうですね」「書かれたからにはメンテし続けないといけなくなるので、そういうプロジェクトの人がそう回答していることが多いのかなと想像してみました」
「プロジェクト規模: データベースのテーブルが100個を超えてるプロジェクトが3割ほどある↓」「テーブル100個ですか...」「Railsアプリが育つとテーブル数もこのぐらいにはなりますよ」「Railsで書かれたプロジェクトがそれだけ育って大きくなったという傾向をある程度表しているかなと思います: ただこのアンケートの母数が142とあるので調査としてはかなり小規模ですが」「そのつもりで読まないといけないということですね」
How big is your project.
Number db tables is a metric everyone understands.
- 30% 100-∞ tables
- 30% 50-100 tables
- 30% 20-50 tablesI'm glad we didn't ask for LOC here :) pic.twitter.com/D6WfuPw6SD
— Tomasz Wróbel (@tomasz_wro) January 11, 2021
「チームの規模↓は三分の一ぐらいが1〜3人ぐらいか: Railsだとそのぐらいの規模のチーム編成が多いでしょうね」
How big is your team?
Most people work in teams of _two or three_.
At least it's Biblical. pic.twitter.com/yzNA61SHbr
— Tomasz Wróbel (@tomasz_wro) January 11, 2021
「テスト1件あたりの実行時間↓は、半分以上が5秒以内」「あ、5分かと思ったら5秒だった😅」「テスト全体じゃなくてテスト1件あたりの実行時間ならこのぐらいの感じかな」「しかしシングルテストで1分以上かかるようなテストを書くことってあるかな?」「結合テストなんかだとそのぐらいかかることもあるかもしれませんね」
How long does it take to run a single test case on your dev machine?
I was really curious about this one.
Actually I'm surprised with the results. pic.twitter.com/qC0nSzIlot
— Tomasz Wróbel (@tomasz_wro) January 11, 2021
「アンケートの母数の小ささを割り引く必要はありますが、Railsアプリ開発のテストに関するアンケートとしてはだいたい自分の感じるところに近そうに思えますね」
⚓ その他Rails
つっつきボイス:「今ならDockerでやるかなと思いつつ、新し目の記事なので一応貼ってみました」「Ruby 2.7.2を使ってる」「WSLにも2が付いてませんね」
参考: WSL 2 と WSL 1 の比較 | Microsoft Docs
「お、この記事ではWindows版のPostgreSQL↓をインストールしてますね」「あ、ホントだ」「GUIインストーラですか」
参考: PostgreSQL: Windows installers
「それにしてはapt-get
も使ってるのが妙だな...起動もLinuxのsudo -u postgres -i
コマンドだし」「あ、pgAdmin↓をインストールするのにapt-get
を使ってるのか」
「Qiitaによくありそうなやってみた系記事かなという印象ですね」
前編は以上です。
バックナンバー(2021年度第1四半期)
週刊Railsウォッチ(20210120後編)Ruby 3.0の新機能で遊ぶ、RubyスニペットをJSに変換するRuby2JS、rspec-parameterized gemほか
- 20210113後編 Ruby 3.0 Ractor解説記事、Vercelホスティングサービス、教育用OS xv6ほか
- 20210112前編 Active Recordの範囲指定バリデーション改善、soleとfind_sole_byメソッド、AlgoliaとRailsほか
今週の主なニュースソース
ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSやruby-jp SlackやRedditなど)です。