- Ruby / Rails関連
週刊Railsウォッチ: Rails公式の"rails-new"ツールでRailsプロジェクトをセットアップほか(20240409前編)
こんにちは、hachi8833です。
🔗Rails: 先週の改修(Rails公式ニュースより)
🔗 Action Viewとヘルパーのドキュメントが一般プレビュー開始
- PR: [RF-DOCS] Action View Overview Guide [ci-skip] by bhumi1102 · Pull Request #51435 · rails/rails
- PR: [RF-DOCS] Action View Helpers Documentation [ci-skip] by Ridhwana · Pull Request #51432 · rails/rails
- コード例を追加し、既存のコード例も更新。
- パーシャルに関連するトピックをこのガイドに統合する。
- 文の流れと読みやすさ向上のため、セクションを再構成。
- Action Viewがどのように適合するかを明確にする形で序文を書き換え。
#51435 Detailより
- AssetTagHelperでは多数の
*_tag
ヘルパーについて説明しているが、*_url
ヘルパーや*_path
ヘルパー(これらはAssetUrlHelperにある)については言及していたりいなかったりしている。こうしたヘルパーは知っていれば役には立つが利用頻度は低いと思われ、言及されている場合やされていない場合もあって不完全なので(*_tag
ヘルパーには対応するものがあるか、さもなければ基本的なasset_path
やasset_url
を利用する)、これらのバリアントをすべて網羅する価値はないと思われ、むしろ削除したい。言及したいのであれば、同じサブセクション内にまとめるか、関連する*_tag
セクションの例としてまとめることも可能。- キャッシュヘルパーでは他にもいくつかの情報を利用できる。フラグメントAPIにリンクする価値はなく、むしろキャッシュガイドのフラグメントキャッシュの項で詳しく説明されているので、そちらにリンクする方が価値があると思う。その例を拡張すれば少なくともレコードを取得する例を示すことも可能。
content_for
ではcontent_for?
の例も何らかの形で示す方がよいかもしれない。- このガイドではフォームヘルパーについては言及せず、別ガイドへのリンクを示すにとどめたいが、そのパラグラフをもっと明確にできるかもしれない。
escape_javascript
にコード例を付けてもよい(APIにあるものはjQueryとのつながりが強そうなのでそれではないものにしたい: JSにRubyを埋め込む他のコード例なのかもしれない)。- rails-html-sanitizer gemへの言及はリンクに変えてもいいかもしれない。
- メモ: エスケープなしの'<'、'>'、'&' が出力に含まれてブラウザが混乱する可能性があることについても言及すべきだろうか?
- UrlHelperには
current_page?
やmail_to
などよく使われているものが他にもある(全部のメソッドを解説する必要はなく、最もよく使われるものだけでよい)。- このガイドではCsrfHelperについて説明する必要はなさそう(CsrfHelperのような必要かどうかがよくわからないものについては追加していない、たぶんスキップしてもよさそう)。
- TextHelperのセクションを追加して、
simple_format
、truncate
、excerpt
あたりの説明を加えるといいかもしれない(繰り返すが全部を網羅するよりも最もよく使われるものだけでよい)。- TagHelperのセクションを追加して、
content_tag
やtag
についてはそこで説明してもよさそう。- 冒頭の「このガイドの内容:」を更新。
- 全セクションの形式を同じような形に揃える: ヘルパーの下に何らかの説明文を置き、それからメソッドについて書く。
- (markdownの)改行位置をスタイルガイドの通りにする。
- 非推奨のベンチマークを削除。
- 言い回しが明確になるよう調整。
capture
とcontent_for
の説明をわかりやすくした。- 必要に応じてコード例を追加。
- このガイドのWIP表示を削除。
- セクションを並べ替えた。
#51432 Detailより抜粋
つっつきボイス:「Action Viewとヘルパーのドキュメント更新に対して一般からのフィードバックが募集されています」「セクションの順序も含めて大幅に変えようとしていますね」「ちなみに更新に含まれているdocuments.yamlはガイドにWIP(work-in-progress:作業中)を表示するかどうかの制御にも使われています」
「すべてのヘルパーを見たければAPIドキュメント↓で参照すればいいので、ガイドのドキュメントに何もかも盛り込む必要はないというのはわかる: ガイドのドキュメントは、その名の通りどんな機能・使い方・注意点があるのかという概要を示す方に注力する方がいいでしょうね👍」
🔗 config.active_record.permanent_connection_checkout
が追加
参考: #50793
ActiveRecord::Base.connection
は「エラーを発生させる」「非推奨警告を表示する」「どちらも行わない」のどれにするかを制御する。
ActiveRecord::Base.connection
は、そのコネクションのプールからデータベースコネクションをチェックアウトして、リクエストやジョブが完了するまでリース中(貸出中、専有中)のままにする。この振る舞いは、利用可能なコネクション数よりも多くのスレッドやfiberが使われる環境では望ましくない場合がある。この
ActiveRecord::Base.connection
コンフィグを使うと、ActiveRecord::Base.connection
をトラッキングして削除し、ActiveRecord::Base.with_connection
を代わりに使う形で移行しようと思えばできるようになる。このコンフィグのデフォルトの振る舞いは変更されておらず、現時点ではデフォルトの振る舞いを変更する予定はない。
まだ足りないのは「
.with_connection
に似ているが.connection
がチェックアウトを永続化しない形で、レガシーコードをラップする方法」かもしれない。たぶん.with_connection
キーワード引数の形にすべきだろうか?@matthewd、何か意見があればよろしく。
同PRより
つっつきボイス:「この#51349は、この間からbyrootさん(PR作成者の別名)が取り組んでいたコネクションのリース周りの改修でも言及されていたプルリクです(ウォッチ20240402)」「アプリ開発者がActiveRecord::Base.connection
の扱いについて制御可能にするコンフィグが追加されたという話ですね」
🔗 ActiveSupport::BacktraceCleaner
でdeep copyされていない項目があったのを修正
ActiveSupport::BacktraceCleaner
を拡張して、複製やクローンのときにfilters
とsilencers
を複製するよう修正。従来は、複製によって内部の
filters
とsilencers
の配列が共有され、ステートが漏洩していた。Jean Boussier
同Changelogより
つっつきボイス:「BacktraceCleaner
をdup
したときにfilters
とsilencers
がdup
されていなかったので、意図したインスタンス変数と違うものが参照されていたんですね: これはバグ」「シンプルにdup
を追加して修正していますね↓」「BacktraceCleaner
は使った覚えがあまりないかも」
# activesupport/lib/active_support/backtrace_cleaner.rb#L113
+ def initialize_copy(_other)
+ @filters = @filters.dup
+ @silencers = @silencers.dup
+ end
参考: Object#clone
(Ruby 3.3 リファレンスマニュアル) -- dup
はエイリアス
参考: 8.3 Quieter Backtrace -- Ruby on Rails 2.3 リリースノート - Railsガイド
🔗 エラーメッセージで関連付けのオプション候補がすべて表示されるよう修正
動機/背景
このプルリクを作成した理由は、関連付けの
through
オプションをタイプミスしたときに、そのことがエラーメッセージに表示されなかったため。たとえば、以下のような単純なタイプミス
trough
をしたとする。class User < ApplicationRecord has_many :courses has_many :assignments, trough: :courses end
Rails起動時に以下のメッセージが表示されるが、これは誤解を招く。
Unknown key: :trough. Valid keys are: :class_name, :anonymous_class, :primary_key, :foreign_key, :dependent, :validate, :inverse_of, :strict_loading, :query_constraints, :autosave, :before_add, :after_add, :before_remove, :after_remove, :extend, :counter_cache, :join_table, :index_errors (ArgumentError)
注目すべき肝心の
through
がエラーメッセージに表示されていない。詳細
このプルリクでは、関連付けの
HasOne
ビルダーやHasMany
ビルダーでこれらの問題をすべて修正する。その理由は、現在の
ActiveRecord::Associations::Builder::HasMany.valid_options
は、指定されたオプションにthrough
が存在する場合にのみthrough
を追加しているため。def self.valid_options(options) ... valid += [:through, :source, :source_type] if options[:through] ... end
このロジックは
source
やsource_type
の場合にのみ適切と思われるが、through
をエラーメッセージのリストに無条件に追加できない理由がわからない。これはActiveRecord::Associations::Builder::HasOne.valid_options
の略である。パッチを適用することで、問題は以下のように修正される。
Unknown key: :trough. Valid keys are: :class_name, :anonymous_class, :primary_key, :foreign_key, :dependent, :validate, :inverse_of, :strict_loading, :query_constraints, :autosave, :before_add, :after_add, :before_remove, :after_remove, :extend, :counter_cache, :join_table, :index_errors, :through (ArgumentError)
追加情報
自分が何か見落としておらず、これが実際に問題であるとするなら、他にも似たような問題が発生している可能性がある。
同PRより
つっつきボイス:「Unknown keyの関連付け予約語候補リストにthrough
が含まれていなくて困ったのがきっかけで改修したんですね: 修正は地味ですが、よくぞ見つけたという感じ👍」
# activerecord/lib/active_record/associations/builder/has_many.rb#L9
def self.valid_options(options)
- valid = super + [:counter_cache, :join_table, :index_errors]
- valid += [:as, :foreign_type] if options[:as]
- valid += [:through, :source, :source_type] if options[:through]
+ valid = super + [:counter_cache, :join_table, :index_errors, :as, :through]
+ valid += [:foreign_type] if options[:as]
+ valid += [:source, :source_type, :disable_joins] if options[:through]
valid += [:ensuring_owner_was] if options[:dependent] == :destroy_async
- valid += [:disable_joins] if options[:disable_joins] && options[:through]
valid
end
# activerecord/lib/active_record/associations/builder/has_one.rb#L9
def self.valid_options(options)
- valid = super
- valid += [:as, :foreign_type] if options[:as]
+ valid = super + [:as, :through]
+ valid += [:foreign_type] if options[:as]
valid += [:ensuring_owner_was] if options[:dependent] == :destroy_async
- valid += [:through, :source, :source_type] if options[:through]
- valid += [:disable_joins] if options[:disable_joins] && options[:through]
+ valid += [:source, :source_type, :disable_joins] if options[:through]
valid
end
🔗 特定のクエリメソッドやArelでallow_retry
オプションを指定可能になった
コネクションに関連する例外で、冪等(べきとう: idempotent)であることがわかっているSELECTクエリをリトライできるようになった。
自分たち開発者がArelツリーをたどってビルドしたSELECTクエリや、モデルの既知の属性を用いてビルドしたSELECTクエリは冪等であり、コネクションエラー時でも安全にリトライできる。従来は、リクエスト中にコネクションエラーが発生すると
TrilogyAdapter
でActiveRecord::ConnectionFailed: Trilogy::EOFError
が発生することがあった。Adrianna Chang
同Changelogより
動機/背景
#51166の再チャレンジだが、
#select
メソッドによるSQLクエリは安全にリトライ可能という前提を置かず、自分たちがビルドして冪等であるとわかっているクエリだけをリトライする。詳細
このプルリクでは、オプションの
allow_retry
フラグを使うことで2種類のクエリをリトライ可能にする。
- 開発者が
#to_sql_and_binds
でArelツリーをたどって構築したSQLクエリ。
コレクタクラスで新しいretryable
属性を利用する。この属性は、ほとんどのArelノード種別ではデフォルトでtrue
に設定されるが、冪等でないノード種別(関数、SQLリテラル、UPDATE/DELETE/INSERTなど)ではfalse
に設定される。retryable
値は#to_sql_and_binds
から返されて#select_all
で利用され、コールスタックに渡されて最終的にアダプタの#internal_exec_query
メソッドに到達する。既知の属性を用いる
#find
クエリや#find_by
クエリ。
#cached_find_by
でallow_retry: true
を設定してから、これを#find_by_sql
や#_query_by_sql
に渡す。これらの変更によって、安全にリトライ可能であることが開発者側でわかっているクエリについては自動的にリトライできるようになる。
追加情報
検証用:
- テストのカバレッジは十分か?
特定のSQLクエリを生じる可能性のあるActive Record APIをすべてテストするのは困難なので、最もよく使われるものをカバーしてみた。UPDATE/DELETE/INSERTがリトライ不可能であることをテストしようとしたが、これらはトランザクションでラップされているため、最終的にBEGIN
で再接続される。冪等でない可能性のあるArelノードを見逃した可能性はあるか?
なお自分たちは、NamedFunction
とSqlLiteral
は冪等ではないと考えているので、本当はリトライ可能にできるクエリの多くが除外されている可能性もあるが、現時点ではこれが最も安全なオプションとなる。
cached_find_by
が常に冪等なクエリを生成することは保証されているのか?
これは、Post.find
やPost.find_by(title: "foo")
をリトライ可能にする唯一の方法であり、この種のクエリはリトライ可能にすべきだと考えている。SQLのフラグメントを含むfind_by
が引数として渡されると、フラグはリトライ不可に設定される。cc @matthewd
同PRより
つっつきボイス:「冪等であることがわかっているselect系メソッドやfind系メソッドなどにallow_retry
オプションを付けられるようになったそうです」「TrilogyAdapterの場合だけかと思ったらPostgreSQLやMySQLやSQLite3のアダプタでも使えるようになってるのか」「31ファイルも修正されていますね」
「言われてみれば関数とかはまったく同じクエリを実行したときにも冪等にならない可能性はたしかにありますね: 機能追加だから既存の振る舞いは変わらないけど、RDBの種類に依存する部分もあるだろうし、結構複雑なことをやろうとしている感じだけど、冪等にしても大丈夫と思われるクエリをホワイトリスト化することで行う分には大丈夫そう👍」
🔗Rails
🔗 Rails公式の"rails-new"ツール(Ruby Weeklyより)
つっつきボイス:「名前がrails-newなのが面白い」「少し前からGitHubのRailsリポジトリに公式に置かれているツールですが、これまで知りませんでした: Rustで書かれていて、Dockerさえ使えればRubyがインストールされていない環境でも新規Railsアプリを速攻で作れるようです」「なるほど、やっていることはシンプルそう」
「とりあえずこのツールがどんな方向を目指しているかにもよるけど、最近のRailsがサポートしているdevcontainer(ウォッチ20240228)の活用例を模索している感じなのかな」「そういえばREADMEのインストール方法がまだ空欄ですし、まだ作り中っぽい気もしますね」「devcontainerが使えるとGitHub上ですべての作業が完結するようになるので、教育方面とかでRails環境のセットアップを簡略化したりするのにもよさそう👍」「ブラウザ環境だけでRails開発できるようになるヤツですね」
Great video thank you for doing that. For the initial setup of a new rails app check https://t.co/mwsX1dr3TO
I’m still polishing it, but I think it works on windows already.
— Rafael França 🇧🇷 (@rafaelfranca) March 20, 2024
インストール方法がREADMEに書かれていなかったので、gh repo clone rails/rails-new
してcargo build
したデバッグ版バイナリで動かしてみましたが、私の環境ではコケたのでDockerfileを取り急ぎ修正して動かしてみました↓。
▶インストールログ(クリックで展開)
rails$ ~/deve/rust/rails-new/target/release/rails-new myapp
[+] Building 11.4s (7/7) FINISHED docker:desktop-linux
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 489B 0.0s
=> [internal] load metadata for docker.io/library/ruby:3.3.0 2.2s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> CACHED [1/3] FROM docker.io/library/ruby:3.3.0@sha256:bf1afb92b390d90815b83ebf175c243b21e6e5204e040d3ca03a2f4dce3f 0.0s
=> [2/3] RUN groupadd myapp -g 1000 -o && useradd myapp -u 1000 -g 1000 -o --create-home --shell /bin/bash 0.2s
=> [3/3] RUN if [ -z "7.1.3" ] ; then gem install rails ; else gem install rails -v 7.1.3 ; fi 8.8s
=> exporting to image 0.2s
=> => exporting layers 0.2s
=> => writing image sha256:0633a814d33d1294d2a2c5b30525e5c62654e040a70b78dffc54551523d12a17 0.0s
=> => naming to docker.io/library/rails-new-3.3.0-7.1.3 0.0s
View build details: docker-desktop://dashboard/build/desktop-linux/desktop-linux/tu0c80vtgqgxw8o5nngguxvva
What's Next?
View a summary of image vulnerabilities and recommendations → docker scout quickview
create
create README.md
create Rakefile
create .ruby-version
create config.ru
create .gitignore
create .gitattributes
create Gemfile
run git init -b main from "."
Initialized empty Git repository in /Users/hachi8833/deve/rails/myapp/.git/
create app
create app/assets/config/manifest.js
create app/assets/stylesheets/application.css
create app/channels/application_cable/channel.rb
create app/channels/application_cable/connection.rb
create app/controllers/application_controller.rb
create app/helpers/application_helper.rb
create app/jobs/application_job.rb
create app/mailers/application_mailer.rb
create app/models/application_record.rb
create app/views/layouts/application.html.erb
create app/views/layouts/mailer.html.erb
create app/views/layouts/mailer.text.erb
create app/assets/images
create app/assets/images/.keep
create app/controllers/concerns/.keep
create app/models/concerns/.keep
create bin
create bin/rails
create bin/rake
create bin/setup
create Dockerfile
create .dockerignore
create bin/docker-entrypoint
create config
create config/routes.rb
create config/application.rb
create config/environment.rb
create config/cable.yml
create config/puma.rb
create config/storage.yml
create config/environments
create config/environments/development.rb
create config/environments/production.rb
create config/environments/test.rb
create config/initializers
create config/initializers/assets.rb
create config/initializers/content_security_policy.rb
create config/initializers/cors.rb
create config/initializers/filter_parameter_logging.rb
create config/initializers/inflections.rb
create config/initializers/new_framework_defaults_7_1.rb
create config/initializers/permissions_policy.rb
create config/locales
create config/locales/en.yml
create config/master.key
append .gitignore
create config/boot.rb
create config/database.yml
create db
create db/seeds.rb
create lib
create lib/tasks
create lib/tasks/.keep
create lib/assets
create lib/assets/.keep
create log
create log/.keep
create public
create public/404.html
create public/422.html
create public/500.html
create public/apple-touch-icon-precomposed.png
create public/apple-touch-icon.png
create public/favicon.ico
create public/robots.txt
create tmp
create tmp/.keep
create tmp/pids
create tmp/pids/.keep
create tmp/cache
create tmp/cache/assets
create vendor
create vendor/.keep
create test/fixtures/files
create test/fixtures/files/.keep
create test/controllers
create test/controllers/.keep
create test/mailers
create test/mailers/.keep
create test/models
create test/models/.keep
create test/helpers
create test/helpers/.keep
create test/integration
create test/integration/.keep
create test/channels/application_cable/connection_test.rb
create test/test_helper.rb
create test/system
create test/system/.keep
create test/application_system_test_case.rb
create storage
create storage/.keep
create tmp/storage
create tmp/storage/.keep
remove config/initializers/cors.rb
remove config/initializers/new_framework_defaults_7_1.rb
run bundle install
Fetching gem metadata from https://rubygems.org/...........
Resolving dependencies...
Fetching rake 13.2.0
Installing rake 13.2.0
Fetching bigdecimal 3.1.7
Fetching drb 2.2.1
Fetching public_suffix 5.0.5
Fetching bindex 0.8.1
Fetching msgpack 1.7.2
Fetching regexp_parser 2.9.0
Fetching io-console 0.7.2
Fetching rubyzip 2.3.2
Installing bigdecimal 3.1.7 with native extensions
Installing drb 2.2.1
Fetching websocket 1.2.10
Installing io-console 0.7.2 with native extensions
Installing bindex 0.8.1 with native extensions
Installing rubyzip 2.3.2
Fetching sqlite3 1.7.3 (aarch64-linux)
Installing regexp_parser 2.9.0
Fetching puma 6.4.2
Installing public_suffix 5.0.5
Installing msgpack 1.7.2 with native extensions
Fetching sprockets 4.2.1
Installing websocket 1.2.10
Fetching net-imap 0.4.10
Fetching net-smtp 0.5.0
Installing puma 6.4.2 with native extensions
Installing sprockets 4.2.1
Installing net-smtp 0.5.0
Installing net-imap 0.4.10
Fetching xpath 3.2.0
Installing xpath 3.2.0
Fetching addressable 2.8.6
Installing addressable 2.8.6
Installing sqlite3 1.7.3 (aarch64-linux)
Fetching rdoc 6.6.3.1
Fetching selenium-webdriver 4.19.0
Fetching capybara 3.40.0
Installing rdoc 6.6.3.1
Fetching reline 0.5.0
Installing capybara 3.40.0
Installing reline 0.5.0
Fetching irb 1.12.0
Installing irb 1.12.0
Fetching debug 1.9.2
Installing debug 1.9.2 with native extensions
Installing selenium-webdriver 4.19.0
Fetching bootsnap 1.18.3
Installing bootsnap 1.18.3 with native extensions
Fetching activesupport 7.1.3.2
Installing activesupport 7.1.3.2
Fetching activemodel 7.1.3.2
Fetching actionview 7.1.3.2
Fetching activejob 7.1.3.2
Installing activemodel 7.1.3.2
Fetching activerecord 7.1.3.2
Installing actionview 7.1.3.2
Fetching actionpack 7.1.3.2
Fetching jbuilder 2.11.5
Installing activejob 7.1.3.2
Installing activerecord 7.1.3.2
Installing actionpack 7.1.3.2
Installing jbuilder 2.11.5
Fetching actioncable 7.1.3.2
Fetching activestorage 7.1.3.2
Fetching actionmailer 7.1.3.2
Fetching railties 7.1.3.2
Fetching sprockets-rails 3.4.2
Installing actioncable 7.1.3.2
Installing activestorage 7.1.3.2
Fetching actionmailbox 7.1.3.2
Fetching actiontext 7.1.3.2
Installing actionmailer 7.1.3.2
Installing railties 7.1.3.2
Installing sprockets-rails 3.4.2
Installing actionmailbox 7.1.3.2
Installing actiontext 7.1.3.2
Fetching importmap-rails 2.0.1
Fetching stimulus-rails 1.3.3
Fetching turbo-rails 2.0.5
Fetching web-console 4.2.1
Fetching rails 7.1.3.2
Installing importmap-rails 2.0.1
Installing stimulus-rails 1.3.3
Installing turbo-rails 2.0.5
Installing web-console 4.2.1
Installing rails 7.1.3.2
Bundle complete! 14 Gemfile dependencies, 81 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
run bundle lock --add-platform=x86_64-linux
Writing lockfile to /Users/hachi8833/deve/rails/myapp/Gemfile.lock
run bundle binstubs bundler
rails importmap:install
apply /usr/local/bundle/gems/importmap-rails-2.0.1/lib/install/install.rb
Add Importmap include tags in application layout
insert app/views/layouts/application.html.erb
Create application.js module as entrypoint
create app/javascript/application.js
Use vendor/javascript for downloaded pins
create vendor/javascript
create vendor/javascript/.keep
Ensure JavaScript files are in the Sprocket manifest
append app/assets/config/manifest.js
Configure importmap paths in config/importmap.rb
create config/importmap.rb
Copying binstub
create bin/importmap
run bundle install
Bundle complete! 14 Gemfile dependencies, 81 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
rails turbo:install stimulus:install
apply /usr/local/bundle/gems/turbo-rails-2.0.5/lib/install/turbo_with_importmap.rb
Import Turbo
append app/javascript/application.js
Pin Turbo
append config/importmap.rb
run bundle install
Bundle complete! 14 Gemfile dependencies, 81 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
Run turbo:install:redis to switch on Redis and use it in development for turbo streams
apply /usr/local/bundle/gems/stimulus-rails-1.3.3/lib/install/stimulus_with_importmap.rb
Create controllers directory
create app/javascript/controllers
create app/javascript/controllers/index.js
create app/javascript/controllers/application.js
create app/javascript/controllers/hello_controller.js
Import Stimulus controllers
append app/javascript/application.js
Pin Stimulus
Appending: pin "@hotwired/stimulus", to: "stimulus.min.js"
append config/importmap.rb
Appending: pin "@hotwired/stimulus-loading", to: "stimulus-loading.js"
append config/importmap.rb
Pin all controllers
Appending: pin_all_from "app/javascript/controllers", under: "controllers"
append config/importmap.rb
run bundle install
Bundle complete! 14 Gemfile dependencies, 81 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
🔗 Ruby開発者が愛する14のツールとgem(Ruby Weeklyより)
つっつきボイス:「以前翻訳したEvil Martiansのgem記事↓は、Railsアプリ本体の機能強化に使うものが中心という感じでしたが、上のtestdoubleの記事は、どちらかというとツール寄りのgemを紹介している感じですね」
「rack-miniprofilerとかは定番の便利ツールだけど、それと連携してパフォーマンスチェックするdebugbarは初めて見た」「SQLを整形する系のツールもいくつかありますね」「http://localhost:3000/rails/info/routes
がちゃんとツールとして紹介されているのはエラい」「Rails標準の機能ですよね」
参考: 6.1 既存のルールを一覧表示する -- Rails のルーティング - Railsガイド
ルーティングといえばこちらも標準の機能ですね↓。
🔗 Active Supportの宣言的test
ヘルパーでテスト間のステートを共有するcontext
ヘルパーを実装するならこうかもしれない(Ruby Weeklyより)
つっつきボイス:「RSpec作者のSteven Bakerさんによるgistだそうです」「RSpecのcontext
的なことをminitestでやれるようにするということなのかな?気持ちはわからなくもないけど、minitestの並列性や速度が落ちそうだしテストがもろくなりそうなのであんまりやりたくないかも」「あら、gistの冒頭にこんなことが書かれているのでジョークっぽいですね↓」
Active Supportの宣言型スタイルを利用するときに、Minitestの宣言型スタイルでコンテキストヘルパーを実装する方法のデモンストレーション。
これはRubyで私が好きなお楽しみハックだが、おそらく使うべきではない。
いや、むしろ絶対に使わないこと。しかし私が20年前にRSpecをリリースしたときにも同じことを言っても聞いてもらえなかったのに、今になって聞いてもらえるだろうか。
こういうのを賢いと思う人や、私が作ったものを気に入ってくれた形はぜひメールにてご一報を。テストスイートの回復力を高めてコードを改善する作業を引き受けます。ファンメールはsteven@stevenrbaker.comまで。
このコードが不安定な理由などについて楽しく話し合いたい。 私はRubyが大好きである。
同gistより
🔗 その他Rails
Just as `where` accepts a hash condition where keys represent fields, Rails now allows hashes as arguments for `select`, where keys represent fields and values represent aliases. #RailsTip pic.twitter.com/eOzYVEnJRs
— Ruby on Rails (@rails) March 27, 2024
つっつきボイス:「今回も公式の#RailsTip
から見繕いました」「お〜、select
で文字列にいちいちAS
を書かなくても、こうやってハッシュ形式で渡すとArelがAS
を補ってくれるのか!」
# 以下のように書かなくても
Post.select(
'posts.id AS post_id, posts, title AS post_title'
)
# 今は以下のように書ける
Post.select(
posts: {
id: :post_id,
title: :post_title
}
)
前編は以上です。
バックナンバー(2024年度第2四半期)
週刊Railsウォッチ: solid_queueとmission_control-jobsが正式にRailsのgemに、Rubyの"チルド"文字列ほか(20240402)
ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSやruby-jp SlackやRedditなど)です。
週刊Railsウォッチについて
TechRachoではRubyやRailsなどの最新情報記事を平日に公開しています。TechRacho記事をいち早くお読みになりたい方はTwitterにて@techrachoのフォローをお願いします。また、タグやカテゴリごとにRSSフィードを購読することもできます(例:週刊Railsウォッチタグ)