- Ruby / Rails関連
週刊Railsウォッチ: Rails 7.0.2の改修内容、receipts gemでレシートを作成ほか(20220214前編)
こんにちは、hachi8833です。
🔗Rails: 先週の改修(Rails公式ニュースより)
今回は少し趣向を変えて、7.0.2に入った改修のうち直近かつ取り上げていなかったものを中心に見繕ってみました。
🔗 Active StorageのDirectUploadsController
にservice_name
を渡す機能がいったん外された
- PR: Revert #38957 by gmcgibbon · Pull Request #44287 · rails/rails
- revertされたPR: Pass service_name param to DirectUploadsController by DmitryTsepelev · Pull Request #38957 · rails/rails
- revertされたPR: Fixes for multi-service direct uploads by gmcgibbon · Pull Request #43650 · rails/rails
- 関連issue: Issues with new direct upload support for multiple storage services and an alternative · Issue #43971 · rails/rails
つっつきボイス:「そういえば7.0.2で削除された機能がありましたね」「Direct Uploadのストレージエンジンを切り替えられるservice_name
オプション機能が削除されたようですね」「この機能があると6.xからのアップグレードが難しくなってしまったので外したみたい」「完全になくなったわけではなくて、再実装が終わるまでいったん外すことにしたようです」「あ、そういうことですか」
「複数のオブジェクトストレージを切り替えながら混ぜて使うことは普通あまりないと思うので、この機能を使っている人はそんなにいないんじゃないかな」「AWSとGCPのストレージを切り替えて使うとか、たしかにあまりやらなさそうですね」
🔗 schema.rbに現在のRailsバージョンも含めるようになった
#42297以降のRailsはMySQLの
datetime
カラムのprecision
(精度)を6で生成するようになった。つまり、6.1から7.0にアップグレードすると、データベーススキーマを読み込んだときに新しいprecision
値が使われるようになり、productionのスキーマと合わなくなってしまう。
これを回避するため、ActiveRecord::Schema
クラスを6.1の実装でフリーズし、ActiveRecord::Migration
と同様の仕組みで他のバージョンにアクセスできるようにする。
スキーマダンパーは今後以下のようにRailsのバージョンを含む新しいフォーマットを生成するようになる。
ActiveRecord::Schema[7.0].define
つっつきボイス:「こちらはDBのスキーマファイルにRailsのバージョンを含めるようにした修正」「マイグレーションファイルの[7.0]
みたいな感じでschema.rbにもバージョンを含めるんですね」
「Rails 7.0では一部のカラムのデフォルト値が少し変わったんですよ」「そういえばMySQLでprecision
が6に変わったとか書かれていますね」
「./bin/rails db:setup
するとschema.rbからスキーマを読み込むので、そのままだとRails 6.1からアップグレードするときにスキーマのデフォルト値が変わってしまうことがある」「あ〜そういうことですか」「./bin/rails db:migrate
するのであれば、マイグレーションファイルに含まれているRailsのバージョン情報を使って適切に移行できるんですが、./bin/rails db:setup
だとマイグレーションファイルを参照せずにschema.rbから直接スキーマを読み込むので、schema.rbにもRailsのバージョンを付加して適切なデフォルト値でスキーマを読み込むようにしたということですね」「なるほど」
🔗 関連付けにリフレクションがない場合のエラー表示が改善
つっつきボイス:「これはエラー表示の改善ですね: 元はテーブル名しか表示されなかったのがモデル名や関連付け名を表示するようになった↓」「NoMethodError
もArgumentError
エラーに変わったんですね」「情報が足りないと何が起こっているのかわからないことがよくある」「そうそう」「エラーメッセージが親切なのは大事👍」
# 改修前
Post.where.associated(:cars).to_a # Post does not have association named `cars`
=> NoMethodError: undefined method `table_name' for nil:NilClass
# 改修後
Post.where.associated(:cars).to_a
=> ArgumentError: An association named `:cars` does not exist on the model `Post`.
🔗 record
という名前の関連付けを保存するとエラーになるのを修正
record
という名前に関連付けられているリレーションを持つモデル(ポリモーフィックなものなど)のレコードを保存すると、record_changed?
がbelongs_to :record
で上書きされるためActive Recordでエラーが発生する。
同PRより
つっつきボイス:「record
という名前が使われているとエラーになっていたそうです」「なるほど、Active Recordが動的に生やしたrecord_changed?
が誤って動いてしまうので、_record_changed?
のようにアンダースコアを付けて修正したんですね↓」
# activerecord/lib/active_record/autosave_association.rb#L464
- def record_changed?(reflection, record, key)
+ def _record_changed?(reflection, record, key)
record.new_record? ||
association_foreign_key_changed?(reflection, record, key) ||
record.will_save_change_to_attribute?(reflection.foreign_key)
end
「record
という名前はいかにもダメな名前っぽいけど、現実に使われる可能性はあるかも」「たしかに」「自分もつい最近、さんざん悩んだ末に仕方なくdate
というカラム名を付けました」「何とか_at
にしづらい日付なんですね」
🔗Rails
🔗 GitHub CodeQLにRubyコードのサポートが追加(Ruby Weeklyより)
つっつきボイス:「CodeQLはGitHubのセキュリティチェック機能だそうです」「お〜、図を見た感じでは、QL Compilerで中間言語的なものを生成して、コードから抽出したデータベースクエリをそれで評価するみたい↓」
「Rubyコードのパーサーにはtree-sitterというものを使っている↓」「パーサーで取り出したコードをRDBに保存しているのか、これは面白い」
参考: Tree-sitter|Introduction -- Ruby以外にもいろんな言語向けのラッパーがあります
「記事の話と直接関係ないんですが、CodeQLを眺めているうちにノイマン型アーキテクチャvsハーバードアーキテクチャという図式をちょっと連想しました」「ハーバードアーキテクチャはデータとコードが別腹になるヤツでしたっけ」「CodeQLがやっているように、やろうと思えばノイマンアーキテクチャ的にデータストレージにコードを置いたっていいんだよなと改めて思った次第です」「すごい発想」
参考: ノイマン型 - Wikipedia
参考: ハーバード・アーキテクチャ - Wikipedia
🔗 Liquidタグで動的コンテンツ表示(Ruby Weeklyより)
つっつきボイス:「Liquidって何だろうと思ったら、何かの静的サイトジェネレータでLiquidが使われてたのを少し触った覚えがあります」「Liquidはいわゆるテンプレートエンジンで↓、Shopifyが作ったものですね」「Shopifyはこういうのも作ってるんですね」
「ちょっと懐かしい感じのテンプレートエンジン記法↓」
# 元記事より
liquid("Hi {{ missing_value }}", context: {})
#=> "Hi \{\{ missing_value }}"
liquid("Hi {{ foo", context: {})
#=> "Hi \{\{ foo"
「元記事のテンプレートを見ていてSmartyをちょっと思い出しました」「それ、今まったく同じこと思いました😆」「Smartyとは?」「相当昔からあるPHPのテンプレートエンジンですね」「PHPやってたのでSmarty懐かしいです、今も現役なのか」
🔗 receipts: Railsで領収書やインボイスのPDFを手軽に作成(Ruby Weeklyより)
つっつきボイス:「領収書やインボイスを作成するからreceiptsというそのまんまの名前」「Railsエンジンではなく単なるgemなんですね」
「PDF生成にはprawnを使っているらしい↓」
「書式のカスタマイズやi18nにも対応しているようですし↓、この書式ベースでいいなら使ってみてもいいんじゃないかな」「領収書やインボイスの書式はそんなに大きく変わらなさそうですよね」「ただ国によって税制なども異なるし、特に日本の業務案件だとgemの書式そのままでOKということはまずありませんけどね」「そこなんですよね...」「PDF生成みたいな機能は同じ言語と商慣習を共有している国で作られたものが安心感ある」
# 同リポジトリより
line_items: [
[I18n.t("receipts.date"), created_at.to_s],
[I18n.t("receipts.product"), "GoRails"],
[I18n.t("receipts.transaction"), uuid]
]
🔗 paralines: スレッドをわかりやすく表示 (Ruby Weeklyより)
つっつきボイス:「パララインズ?」「お〜READMEの動画↓を見たら一発で理解できた: かっこいい👍」「見せ方がうまいですね」「1行1スレッド的に表示している感じ」
「しかもコードはたった170行ですって」「できてから1か月も経ってないからすごく新しい」
「ところでこのRubyコードはTabでインデントされていますね」「スペースのインデントじゃないのか」「これは珍しい」
「デモ画像で凄いと思えるのがいい👍」
🔗 ViewComponentsとTurbo-Streamingを組み合わせる(Hacklinesより)
つっつきボイス:「thoughtbotの記事です: Turbo-StreamingとViewComponentsは割と仲がよさそうかなと思って取り上げてみました」
「なるべくRubyで書きたいならViewComponentsでやってみてもいいかもしれませんね」「なるほど、ViewComponentsはどこかで試してみたい気持ちがちょっとあります」「自分は最終的にHTMLを出力するならRubyで書かなくてもいいのではという気持ちがありますけどね」「それわかります」
# 同記事より
--- a/app/controllers/messages_controller.rb
+++ b/app/controllers/messages_controller.rb
def create
- @message = Message.create(body: params[:body])
+ @message = Message.new(body: params[:body])
+
+ if @message.save
+ Broadcast::Message.append(message: @message)
+ end
respond_to do |format|
format.html { redirect_to messages_path }
format.turbo_stream
end
end
🔗 Rails 6->Rails 7アップグレード
つっつきボイス:「ぼくの記事だ〜」「アップグレードお疲れさまです」「JavaScriptがなかなか動かなくて書くのに2週間ぐらいかかっちゃいました」
「turbo-railsがちゃんとpin
されてる」「pin
するだけでJSのコードがCDNからやってくるのってちょっと感動ですよね」「そうそう」
# 同記事より
# config/importmap.rb
pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true
# turboはhotwiredのjsにpinづけされてる。
# こうして名前と呼び出し元をマッピングすることでapplication.js内でimportするだけで呼び出しが可能になる。
「importmap-railsだとデプロイが軽くなるのがうれしいですね: Bootstrapもプリコンパイル済みのJSコードでよければimportmap-railsでpin
できますし」「最初私もそれでRails 7とimportmap-railsでBootstrapのpin
を試してみたらできたんですが、Bootstrapを拡張しようとしたらやっぱりjsbundling-rails経由でビルドが必要みたいです😢」「そうそう、Sassの変数が絡んでくるものがあると無理」「まさにそれだったので、最終的にBootstrapをやめてtailwindcss-railsに宗旨変えしました」「Bootstrapで変数をカスタマイズし始めるとつらくなりがちなので、それでいいんじゃないでしょうか☺️」「変数カスタマイズはつらいですよね」
「ところで、importmapって表記ゆれが甚だしいですよね、import-mapsだったりImport mapsだったり」「そうそう、公式の表記も今ひとつわからないので、自分はimportmap-railsのgem名で揃えることがよくあります」「最近はimportmapと書くのが多いような気もするけどよくわからない」「やべ、自分も表記ゆれ直しておこうっと(直しました)」
その後で続きの記事も公開されました↓
参考: Rails7にしたあとRuby3.1 + Yjit & Rails7.0.2にアップグレードする | srockstyle
Qiitaでしょっちゅう「 config.consider_all_requests_local = true を付ければOK 」っていう記事を見かけたので、「お前ら全員、やめんかい!」って思って書いた記事がこれ。そのおかげか、最近はほとんど見かけなくなった気がする。 https://t.co/p3mO7Kt6EQ
— Junichi Ito (伊藤淳一) (@jnchito) February 8, 2022
「これはjnchitoさんの言うとおりで、production環境でconfig.consider_all_requests_local = true
にするのは絶対やめるべき」「そんなことをしたらデバッグコンソールからいろいろ見えちゃう」「経験の少ない人がproductionのデバッグでそうしたくなる気持ちはわからなくもないけど、envが露出したりしたら本気で危ない」
「どのフレームワークでもデバッグコンソールは非常に強力なので、productionでさらしてはいけない」「そうそう」「慣れないうちは程度の差はあれ一度はこのようなことをやってしまいがちですが、しないに越したことはありません」
昨日書いたQiita記事です。descriptionを英語で書くなら使い分けに多少気を付けた方がいいですが、日本語で書くなら別にどれでもいいんじゃね?と思う人です。
RSpecでit / example / specifyはどのように使い分けるのか?〜日本語で書くならexampleって本当?〜 https://t.co/02V5wH3g1N
— Junichi Ito (伊藤淳一) (@jnchito) February 9, 2022
「it
とexample
とspecify
の使い分けか」「どちらかというと英語圏での利便性っぽいですね」「it
はsubject
があることを前提にした代名詞的な使い方で、example
はケースを列挙するときに書くとか、specify
は結果に名前を付けるとか、原則論的にはそういう感じかな」
「自分はRSpecのそういう項目は日本語で書いてます」「自分もそうしてますし、特に日本語で書くなら別にit
でいいと思います」「ですよね、it
なら短いし」「failして表示されればどれでも同じですから」
「記事を見ると、it
は英語で書いてexample
は日本語で書くという流派もあるらしいけど、見たことないかも」「そんなローカルルールがあるんですか」
「ところでこんな感じの書き方↓って、昔BDD(ビヘイビア駆動開発)の流れでテストを自然言語に近い形で書くのが流行ったときにcucumberやturnipでやってたりしましたね」「そういえばturnipはちょっと使ってみたけど結局やめました」
# 同記事より
RSpec.configure do |config|
config.alias_example_group_to :次の仕様を記述する
config.alias_example_to :次のような振る舞いを持つこと
end
次の仕様を記述する "四則演算" do
次のような振る舞いを持つこと "1足す1は2である" do
expect(1 + 1).to eq 2
end
end
前編は以上です。
バックナンバー(2022年度第1四半期)
週刊Railsウォッチ: Rubygems.orgのAPIキーに権限スコープが追加、RailsのDBパフォーマンス改善ほか(20220209後編)
- 20220208前編 Rails 6.1を7.0にアップグレードしてみた、PostgreSQLでジョブキューほか
- 20220201後編 Rubygems Adoptionフォームが開設、JetBrains Gateway、NGINX Unitほか
- 20220131前編 Sidekiqが10歳に、BuildKiteのテストを高速化、フィーチャーフラグほか
- 20220126後編 Rubyコンパイラの歴史動画、RubyのWebAssembly対応進む、ぼっち演算子の注意点ほか
- 20220124前編 Webpackerが公式に引退宣言、『Everyday Rails』日本語版がRails 7に対応ほか
- 20220118後編 Ruby 2.5〜3.1ベンチマーク、Opal 1.4、JRubyが20歳に、2022年のCSSほか
- 20220117前編 rails-ujs->Turboアップグレードガイド、RubyとWeb Componentsほか
- 20220112 Rails 7をRuby 3.1で動かす、クックパッドのRuby 3.1解説記事、Rails 6->7更新ほか
今週の主なニュースソース
ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSやruby-jp SlackやRedditなど)です。
週刊Railsウォッチについて
TechRachoではRubyやRailsなどの最新情報記事を平日に公開しています。TechRacho記事をいち早くお読みになりたい方はTwitterにて@techrachoのフォローをお願いします。また、タグやカテゴリごとにRSSフィードを購読することもできます(例:週刊Railsウォッチタグ)