Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

週刊Railsウォッチ(20210426前編)Hotwireの詳細な解説記事3本、Rails 7に入る予定の機能ほか

こんにちは、hachi8833です。

週刊Railsウォッチについて

  • 各記事冒頭には🔗でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
  • 「つっつきボイス」はRailsウォッチ公開前ドラフトを(鍋のように)社内有志でつっついたときの会話の再構成です👄
  • お気づきの点がありましたら@hachi8833までメンションをいただければ確認・対応いたします🙇

TechRachoではRubyやRailsなどの最新情報記事を平日に公開しています。TechRacho記事をいち早くお読みになりたい方はTwitterにて@techrachoのフォローをお願いします。また、タグやカテゴリごとにRSSフィードを購読することもできます(例:週刊Railsウォッチタグ)

🔗Rails: 先週の改修(Rails公式ニュースより)

今回は以下のコミットリストのChangelogを中心に見繕いました。

🔗 disable_joins:オプションが追加

  • 関連付けのjoinsを無効にするオプションを追加

マルチプルデータベースでは、関連付けをデータベース間でjoinできない。
Railsでこのオプションを設定すると、関連付けのJOINを生成する代わりに、2つ以上のクエリを生成するようになる。

このオプションは、以下のようにhas_namy through関連付けに設定する。

class Dog
  has_many :treats, through: :humans, disable_joins: true
  has_many :humans
end

これにより、SQLでJOINを生成するのではなく@dog.treatsで2つのクエリが使われる。

SELECT "humans"."id" FROM "humans" WHERE "humans"."dog_id" = ?  [["dog_id", 1]]
SELECT "treats".* FROM "treats" WHERE "treats"."human_id" IN (?, ?, ?)  [["human_id", 1], ["human_id", 2], ["human_id", 3]]

Eileen M. Uchitelle, Aaron Patterson, Lee Quarella
changelogより大意


つっつきボイス:「disable_joinsはマルチプルデータベースでは欲しい機能でしょうね」「Active Recordが賢くJOINを生成するのを黙らせるのね」

「コミットメッセージを見ると、GitHubの中で使っているコードを切り出したと書かれてました↓」「お〜、GitHubもRailsのマルチプルデータベース機能を使ってるのかな?」

このコードはGitHub内部で用いているgemから切り出したものである。つまりこの実装はproduction環境で常用しているものであり、実験的コードではない。
同コミットメッセージより

「たしかPostgreSQLやMySQLでは同一RDBMS上のデータベース間でJOINが可能ですね」

参考: 4 Methods for joining data from multiple PostgreSQL databases
参考: mysql - Joining two tables from different Databases [SOLVED] | DaniWeb

🔗 新機能: Enumerable#soleが追加

ActiveRecord::FinderMethods#soleに対応するEnumerable#soleを追加。
このメソッドは、enumerableから1個だけ項目を返す。項目がない場合や2個以上の場合はエラーになる。
Asherah Connor
同Changelogより


つっつきボイス:「そういえばActive Recordにもsoleが追加されていましたね(ウォッチ20210112)」「あったあった」「それのEnumerable版なのか」「1件だけあるかどうかをチェックするコードは自分でもよく書くので、Enumerableにもこの機能があるのはいいですね👍」「知っておくとありがたいメソッドになりそう」

「Active Recordのsoleは該当が1件でない場合はエラーになるんですね」「たしかメソッド名をどうするかが議論になってfind_sole_byfind_solely_byなどの候補が出ていた覚えあります」「そうそう」

🔗 ロケールファイルのパスをデフォルトで再帰探索するようになった


つっつきボイス:「デフォルトのロケール読み込みパスが*.{rb,yml}から**/*.{rb,yml}に変わってyamlの再帰読み込みが可能になったんですね↓」「そういえば今までは手動でパスを書いていたかも」「/en//ja/のように言語ごとにロケールのyamlファイルをネストする方が便利ですし、既にベストプラクティスとしてそう書いている人も多いと思うので、再帰読み込みの方をデフォルトにしようということでしょうね」

# railties/lib/rails/engine/configuration.rb#L57
          paths.add "config"
          paths.add "config/environments", glob: "#{Rails.env}.rb"
          paths.add "config/initializers", glob: "**/*.rb"
          paths.add "config/locales",      glob: "*.{rb,yml}"
          paths.add "config/locales",      glob: "**/*.{rb,yml}"
          paths.add "config/routes.rb"
          paths.add "config/routes",       glob: "**/*.rb"

🔗Rails

🔗 willnetさんのHotwire記事


つっつきボイス:「これ、とてもいい記事だと思いました」「そうそう、Hotwireそのものの解説も丁寧ですし、Turbolinksが流行らなかった理由や歴史的経緯も詳しく書かれていてありがたい: Hotwireとは何かという解説だけだとわかりにくくなりがち」「たしかに」

「たしか続き物記事でしたよね?」「はい、『次回に続く』となっていました」「これは楽しみ😋」

同記事で紹介されていたwillnetさんの以下の記事もよさそうですね。

参考: TurbolinksからTurboへの移行 - おもしろwebサービス開発日記


速報: Basecampがリリースした「Hotwire」の概要

🔗 Evil MartiansとEngine YardのHotwire記事


つっつきボイス:「こちらはEvil MartiansによるHotwireの解説記事ですね」「あとEngine YardもHotwire推しの記事を書いているのを見つけました↓」

「今週はHotwire記事が3本も出揃いましたね」「Hotwireのように、HTMLを動的に部分更新をするときにもHTML partialのレンダリングは全部サーバーサイドでやりたいというのは、クライアントJavaScriptとサーバーサイドViewの間をあっちこっち行き来して苦労したことのある人なら一度は思ったことがあるんじゃないかな」「たしかに」「実際似たようなことは昔から行われていて、render_async gem↓もそれに近いと思いますし、大昔のRailsでもlink_to_remoteでパーシャルを直接取得してDOMを更新するなど、泥臭い感じでやってましたね」「ふむふむ」

Rails: render_async gemでレンダリングを高速化(翻訳)

参考: jQueryで link_to_remoteを使う - satake7’s memo

「その意味でHotwireはまったく新しい技術ではないと思いますが、以前は個別に泥臭くやっていた方法を統合された方法で、かつモダンなHTMLでやれるのがメリットなのだろうと考えています」「なるほど!」

🔗 Rails 7に入る機能(Hacklinesより)


つっつきボイス:「Rails 7にどんな機能が入るかを現時点でまとめた記事だそうです」「Railsウォッチで見たことのあるものが大半のようですが、知らない機能もありそうかな」


「画像をlazy loadingする機能が入る↓」「imgタグにloading="lazy"属性を追加できるんですね: ブラウザの画像lazy loading機能を有効にするだけなのでRailsアプリケーションが頑張る話ではなかったか」

参考: Chromeに実装される新機能『loading属性』について解説、ついにブラウザがネイティブで遅延ロードをサポート | コリス


「お、Active Recordにinvert_whereが入るのか↓」「これは知らなかった」「スコープのWHERE条件にNOT ()を付けるんですね」「使うかどうかは微妙かな」

# 同記事より
good_students = Student.where(grade: 80..100)
# SELECT \"students\".* FROM \"students\" WHERE \"students\".\"grade\" BETWEEN 80 AND 100

bad_students = good_students.invert_where
# SELECT \"students\".* FROM \"students\" WHERE NOT (\"students\".\"grade\" BETWEEN 80 AND 100)

has_one: throughも使えるようになるのね↓」「今までできなかったのか!」

# 同記事より
class Dog
  has_many :toys
  has_one :toy_box
end

class Toy
  belongs_to :dog
  has_one :toy_box, through: :dog
end

class ToyBox
  belongs_to :dog
end
toy.build_toy_box
# <ToyBox:0x00007f572007e170 id: nil, dog_id: 3>

toy.create_toy_box
# <ToyBox:0x00005601f2ac09a0 id: 5, dog_id: 3>

「新機能はRails 7が出るまでにまだまだ増えたり変わったりするので、そのつもりで読むのがよいと思います」「そうですね」

🔗 ActiveModel::Attributesの隠された型システム


つっつきボイス:「Active Modelの内部にはビルトイン型がある↓という記事ですね: 内部を解説しているのは貴重かも」「カスタム型の登録をたまに自力でやることがありますけど、Active Model wayでカスタム型を登録できるんですね」「昨年1月の記事ですが、このあたりは大きく変わらないと思うのでよいと思います👍」

# 同記事より
register(:big_integer, Type::BigInteger)
register(:binary, Type::Binary)
register(:boolean, Type::Boolean)
register(:date, Type::Date)
register(:datetime, Type::DateTime)
register(:decimal, Type::Decimal)
register(:float, Type::Float)
register(:immutable_string, Type::ImmutableString)
register(:integer, Type::Integer)
register(:string, Type::String)
register(:time, Type::Time)

前編は以上です。

バックナンバー(2021年度第1四半期)

週刊Railsウォッチ(20210420後編)ShopifyのJITコンパイラYJIT、PicoRuby、DynamoDBの3つの制約ほか

今週の主なニュースソース

ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSやruby-jp SlackやRedditなど)です。

Rails公式ニュース

Ruby Weekly

Hacklines

Hacklines


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。