Railsで爆速開発をしているみなさん、こんにちは。
Railsを書いていると、やれ型がないからクソだの、ダックタイピングが気持ち悪いだの色々言われますよね。
個人的に爆速開発するならRails一択だと思っており、それらの言葉に負けずRailsを書いているのですが、そんなに言われるなら型というのはすごくいいものなんだろうということで、RBSを導入してみました。
RBSとは
RBSとは Ruby 3.0からRubyに標準添付されている型システムの総称であり、ライブラリ名でもあります。
RBSファイルは、Rubyファイルとは別のファイル・別の言語で記述することが特徴です。
class/module名とメソッド名に引数の型と返り値の型を記述します。
TypeScriptでいう.d.ts
ファイルのようなイメージですね。
なので、これがあってもなくても動作には関係なく、あくまで開発者のためのドキュメントという位置づけです。
導入
さて、導入ですが、Ruby3.0からはデフォルトでRBSが導入されているので、特に何もしなくても使えるようになっています。
ただ、ActiveRecordで継承されるメソッドをmodelに対して個別に記述するのは面倒なので、rbs_rails
というgemを使って自動生成するようにしました。
gem 'rbs_rails' # Rails用のRBSファイルを自動生成するgem
gem 'steep' # RBSファイルをチェックするためのgem
bundle install
また、steep
というgemも導入していますが、これはRBSファイルをチェックするためのgemです。
VSCodeの設定
VSCode上でRBSファイルを使うために、VSCodeの設定を変更します。
ローカルではdevContainerを利用しているので、.devcontainer/devcontainer.json
に以下の設定を追加しました。
{
// ...
"customizations": {
"extensions": [
"soutaro.rbs-syntax", // https://github.com/soutaro/vscode-rbs-syntax
"soutaro.steep-vscode" // https://github.com/soutaro/steep-vscode
]
}
}
これでVSCode上で.rbsのファイルのシンタックスハイライトがつくようになり、型定義のエラーやワーニングが表示されるようになります。
使ってみる
さて、使っていきましょう。
まずは簡単な初期設定ファイルを作成していきます。
Gemの型定義ファイルを作成する
bundle exec rbs collection init
bundle exec rbs collection install
gitignoreにも追加しておきましょう。
/.gem_rbs_collection
RBSファイルを生成する
steep init
これで、Steepfileというファイルが生成されます。
以下のように書き換えましょう。
target :app do
signature 'sig'
check 'app'
end
target :lib do
signature 'sig'
check 'lib'
end
rbs_railsでRBSファイルを生成する
bin/rails rbs_rails:all
これで、sigディレクトリにRBSファイルが生成されます。
sig/rbs_rails
ディレクトリが作成されていることを確認してください。
この時点で、一度steep check
を実行してみましょう。
steep check
たくさん怒られましたか?
未定義ファイルがたくさんあると思うので、それを一つずつ解消していきましょう。
RBSファイルを作成する
sigディレクトリ配下の構成は、以下のYouTubeを参考にしています。
sig
├── app # Railsのappディレクトリ配下の自作RBSファイル
├── gems # collectionで対応できなかったgemのRBSファイル
├── rbs_rails # rbs_railsで生成されたRBSファイル
└── standard_lib # 標準ライブラリで不足しているRBSファイル
それでは、appディレクトリ配下のRBSファイルを作成していきましょう。
class Cat < ApplicationRecord
validates :name, presence: true
validates :age, presence: true
def self.ransackable_attributes(_auth_object = nil)
%w[
age
created_at
id
name
updated_at
]
end
def sample_method
name
end
end
class Cat < ::ApplicationRecord
def self.ransackable_attributes: (Object _auth_object) -> Array[String]
def sample_method: () -> String
end
これで、steep check
を実行してみましょう。
無事通りましたか?
それでは、sample_method
をage
に変更してみましょう。
そうするとエラーが出るはずです。
Cannot allow method body have type `::Integer` because declared as type `::String`
::Integer <: ::String
::Numeric <: ::String
::Object <: ::String
::BasicObject <: ::String
↑上記のようなものがVSCode上のProblemsに表示されるはずです。
これで、RBSファイルの型チェックができるようになりました。
やってみての所感
RBSファイルを書くことで、型チェックができるようになり、型のないRubyに型を導入できるようになりました。
面白いなとは思いつつ、これくらいの簡単なものではまだメリットを感じきれないですね…
もうちょっと大きなプロジェクトで使ってみたいと思います。
また、controllerやworkerなどに型を持たせるメリットがあるのか?というところが現状把握しきれていない感じがするので、そこも含めて使っていきたいと思います。
個人的には、ViewComponentのgemがRBS Collectionに含まれていなかったのが意外でした。
まだまだ対応していないgemが多いので、そこも含めて使っていく上での課題になりそうです。
今回はこのあたりで。