はじめに
完全に自分の備忘録です。
Ruby/Rails環境で開発をするときにとても有用な記事を日本語訳して、解説してくれているのでRubyist、Railsエンジニアで知らない人はにわか(暴論)。
読んだ記事はここで管理することで、あれ?なんか読んだことあるな、まぁいっか(読もう)みたいな時間の無駄をなくしたい。
はい、本当は何度も読むこともいいことなのですが、こんだけ読んだぜ!って自己満足するためです。
悪しからず。
週刊Railsウォッチ既読一覧
2017年以前
delegateメソッドを知った。べんり。
コールバックの順序の話。
メソッド探索のように子から実行されると思いきや、クラス定義の読み込みと同じ親から読み込まれる。
ガード節を間違って覚えていた、というか覚えていなかった。
早期復帰というのがわかりやすいんだけど、不正データをもらったら早めにエラーだよって教えてあげることを言っている。
Guard Clauseとは Guard Clauseは、条件分岐のネストを深くしないための技法のひとつで、「ガード節」「ガード条件」「ガード構文」などと訳されることがあります。その動作から早期復帰と呼ばれることもあります。
メソッドの定義元を調べる方法。
Class.method(:method_name).owner
特殊変数一覧のまとめ記事。
Rubyスタイルガイドにも書いてある、Perl由来のぱっと見わからない特殊変数は使わず、
require 'English' して、グローバル変数(?よくわかってない)を利用する。
Railsガイドの日本語訳。
述語メソッド(predicate method)は、論理値(trueかfalseのいずれか)のみを返すメソッドです。
真偽値返す?付きメソッドのことをpredicate methodというのか。しらなかった。
環境変数のSECRET_KEY_BASEについて
Rails.application.secret_key_baseで取得できる
JWT.encodeの第3引数とかで使うのかな(わかってない)
ベストプラクティスのまとめ。
定期的に読み返したい。
ガーベジコレクタとかの話。
雑に読んだ。ほぼわからない。
2つ読んだ。
一つ目は"Rails: ActionMailer::Baseからのrequire "active_support"の脱落を修正"。
この記事を参照することになったきっかけなのだが、
require "active_support"をしないと読み込めない拡張機能があるらしい。
require "active_support/time"はrequire "active_support"しなくても読めた。
Railsは基本的にActive Supportのすべての拡張機能を読み込む。
— Taku Kunita (@takkuso1105) August 2, 2022
Rubyのみの場合は任意の拡張機能をrequireしないと使えない。
ちなみに require 'active_support/time' だけでDateTimeもInteger#hourも使えた。
core_ext拡張は先に require 'active_support' をしないとロードできない。
なぜ。 pic.twitter.com/AlRkmYZz0e
なぞだ。
2つ目はシャドウイングの記事。
Inflectorの意味を調べていたら出てきた記事。
本来の意味は"屈折するもの"らしい。
正直あまりピンとこない。
camelizeとかconstantizeとかたまに使うメソッドがそろっているクラス。
2018年
BPF(Berkeley Packet Filter)の拡張を使って、mallocをprofilingする話。
難しい。
superキーワードの4つの側面。
Rubyではパーレンなしでも継承チェーンをさかのぼってスーパークラスのメソッドの引数を勝手に解釈してくれる。
全然関係ないけど、superってJavaっぽい。
Rubyとの違いは、Javaはコンストラクタは自動で読まれるのでsuper()(パーレンつき)は要らなかったはず。
語弊があるので追記すると、同記事の super vs super() のように引数をそのまま渡したいときはパーレンなし、
引数を渡したくないときは明示的にパーレンをつける必要がある。
引っ掛かりやすい。
Enumerableクラスにいいメソッドがたくさんあるよって話。
injectメソッドの使い方が微妙に変というところに納得しました。
原文からしてそうだけど、#injectの例は微妙に適切じゃないと思う。公式ドキュメントで挙がってる「total + number」の方が良い。ブロックの返り値が次のループのtotalになるので。
これも合わせて読んだ:
とりあえず重要な概念としてのクロージャを読んだ。
クロージャがわかるとメタプロが楽しくなると思っているのだけど、難しいですね。。。
Effective Rubyを読んでいて、to_aryとto_aの違いを調べたら出てきた。
セッション管理について
"Active Recordの#update*系メソッドは要注意"を読んだ。
コールバックが呼ばれるか、引数がどうなるかいつも調べてはすぐ忘れるのでそろそろ覚えたい。
こちらも図で違いについて表現していてよかった。
特にupdateは実質saveということがわかったのでなるべくアップデートのときもsaveを使いたい。
追記:と思ったら、updated_atの値がsaveだと更新されないことがわかった。ので、やはりupdateとsaveは違いました。
Rspecなどのテストでお世話になっていたTimecopというgemがなくても、ActiveRecord::Testing::TimeHelpers
を require
すれば travel_to
というメソッドが使えると言う話。
私の環境ではinclude 'active_record/testing/time_helper' も書かないと使えなかった。
2019年
Railsのエコシステムの話。
2009年の記事の紹介で、Railsコミュニティ活発にしようぜ!という話。(ざっくりすぎ)
あとStrong_parametersでバリデーションする記事について、
フィルターとバリデーションって責務が違うのでそれぞれコントローラー、モデルで
処理を分けるのがRailWayなのかなと思ったのだが、
どうやらAPIモードで利用するときはコントローラーでもバリデーションするような
ユースケースがあるらしい。
たぶんだけど、スキーマ駆動開発とか、APIドキュメントにバリデーションの記載を
含めたくなるようなときに必要なんじゃないかなぁと。
その場合、apipie-railsというgemが便利らしい。
モデル名は単数形・パスカルケース、テーブル名は複数形・スネークケースになるのはRailsエンジニアなら当たり前だけど、
ふと不可算名詞や集合名詞のときにどうなるのかと思って調べたときに読んだ。
ちなみにfurnitureの複数形はfurnituresらしい。fishはfishなので、解せない。
魚の場合は匹ではなく、複数の種類を表す場合はfishesなのは知っているが、
集合名詞、つまり椅子も机も全部でfurnitureと(確か)呼ぶはずなので種類という概念自体がないと思うのだけど。
N+1問題をBulletで発見できないパターン。
実際にハンズオンでやってみた。
集計関数を使ったN+1問題にもRuby3系/Rails7系でやったらしっかり警告してくれた。
今ではもう起きないかも?
その他、rack-mini-profilerをインストールしてクエリ実行を含めた計測を実施した。
親子だけ、データが少なめだったのであまり差が出なかったため、時間あればもう少し大きなデータ、遠い関係でやってみたい。
web | Post Load (1.1ms) SELECT `posts`.* FROM `posts` /*application:Myapp,controller:posts,action:index*/ web | ↳ app/views/posts/index.html.erb:6 web | Comment Load (0.9ms) SELECT `comments`.* FROM `comments` WHERE `comments`.`post_id` = 1 /*application:Myapp,controller:posts,action:index*/ web | ↳ app/views/posts/index.html.erb:12:in `map' web | Comment Load (0.9ms) SELECT `comments`.* FROM `comments` WHERE `comments`.`post_id` = 2 /*application:Myapp,controller:posts,action:index*/ web | ↳ app/views/posts/index.html.erb:12:in `map' web | Comment Load (2.1ms) SELECT `comments`.* FROM `comments` WHERE `comments`.`post_id` = 4 /*application:Myapp,controller:posts,action:index*/
web | SQL (1.2ms) SELECT `posts`.`id` AS t0_r0, `posts`.`name` AS t0_r1, `posts`.`created_at` AS t0_r2, `posts`.`updated_at` AS t0_r3, `comments`.`id` AS t1_r0, `comments`.`name` AS t1_r1, `comments`.`post_id` AS t1_r2, `comments`.`positive_count` AS t1_r3, `comments`.`negative_count` AS t1_r4, `comments`.`created_at` AS t1_r5, `comments`.`updated_at` AS t1_r6 FROM `posts` LEFT OUTER JOIN `comments` ON `comments`.`post_id` = `posts`.`id` /*application:Myapp,controller:posts,action:index*/
web | Post Load (1.0ms) SELECT `posts`.* FROM `posts` /*application:Myapp,controller:posts,action:index*/ web | ↳ app/views/posts/index.html.erb:6 web | Comment Load (1.3ms) SELECT `comments`.* FROM `comments` WHERE `comments`.`post_id` IN (1, 2, 4) /*application:Myapp,controller:posts,action:index*/
web | Post Load (1.1ms) SELECT `posts`.* FROM `posts` /*application:Myapp,controller:posts,action:index*/ web | ↳ app/views/posts/index.html.erb:6 web | Comment Load (1.3ms) SELECT `comments`.* FROM `comments` WHERE `comments`.`post_id` IN (1, 2, 4) /*application:Myapp,controller:posts,action:index*/
tapと#then、#eachと#mapは似ていて、評価結果が返るか、self(レシーバ)が返るかを意識するといいと言う話。
そもそも#thenを知らなかった。使いどころは限られるらしいが、覚えておきたいかも。
2020年
メモ化の話。
初期化メソッドでメモ化って正気か!?って思った。
話変わるけど、存在しないインスタンス変数はnilが返るからややこしい(エラーになると思ってた)。
あとメモ化ってインスタンス変数だけに使われると思ったけど、attr_accessorを設定したら
ゲッターメソッドではローカル変数をメモ化してもいいんだ(それはそう)、と思いました(感想)。
extendとprependとActiveSupport::Concernについて
よく忘れるから根詰めて理解して使わないといけない
環境変数を定数化するのに、 config/initializers/constants.rb
を使うって話がなぜかを知るのに調べた。
全部自動で定数にしてくれればいいのに。。。
いまだに結論は出てない。
2021年
Rubyのinjectを忘れて、reduceで調べたら出た。
いわゆる畳み込み演算。
合わせて読んだ:
ApplicationRecordクラスでボイラープレートみたいなのがあったので調べてみた。
複数RDB連携するときにRDBごとにクラスを使い分けるかんじ?
なんかよくわからなかった。
class ApplicationRecord < ActiveRecord::Base self.abstract_class = true
もともとは2013年の記事だけど、今の環境でも通用するように再編集したっぽい。
#Form Objectに切り出す
まで。
以前はよく話題に挙がったテーブル結合のイディオムの話。
preloadはpre(事前に) + load(読み込む)、クエリは(結合するテーブルが2つなら)2つに分かれる。キャッシュする。関連先で条件(絞込等)が指定できない。大きいデータを取得するとき早い。
eager_loadはeager(熱望して) + load(読み込む)、クエリはleft outer joinで一発、キャッシュはする。関連先で条件(絞込等)が指定できる。条件を指定すればするほど遅い。
つづきは後で書く。。。
週刊Railsウォッチ以外の記事。
Rustはいいぞという話。
人間の脳は差異によって認知が上がるので(謎理論)、
言語ごとの違いで深い洞察を得たいと思っている。
RubyとRustは最初の2文字が同じだけでそれ以外は全然違う(?)。
余裕が出てきたらRustも書けるようになりたい。
2022年
いろいろな%記法。
ひとえに%と言っても、文脈によっていろいろな意味があるのでぜひとも全部覚えておきたいところ。
curl-to-ruby(curlコマンドをRubyコードに変換するサイト)とかおもしろそう。
簡単に触ってみる限りだとcurlの細かいオプションに対応していないっぽい???
Devツールも便利な使い方があるのは知っているんだけど、ほとんど基礎的なことしかできない。。。
学びなおしたいな。
SPA vs. MPAの記事は削除されていて魚拓もなかったけど、はてぶコメント読むとPros&Cons議論がされてておもしろかった。
個人的にはWebで速度気にしたことないから(数秒くらい全然待ってもいい勢)バックエンドもExpressとかNode.jsにして全部TS!とか言うあたおかスーパープログラマの世界線の話かな。
子プロセスをコピーオンライトによってプロセスをfolkするときも従来ほど遅くならない??
全体的にだいぶ難しかった。
また様子見て読み返す。
合わせて読んだ:
fork(2) で子プロセスを生成しなくてすむ。fork(2) はかなり重いシステムコールである。fork(2) が重いので、vfork(2) が作られたくらい重い。ただ、現代の UNIX では copy-on-write の効果により、以前ほど fork(2) が重いわけではない。
シェルからlsコマンドを実行すると、シェルは以下のことを行う。
システムコール fork() を呼び、子プロセスを生成する。
子プロセスは ls を exec() する。
親プロセスであるシェルは、ls の実行が完了するのを待つ (wait する)。
このように,あるコマンド(またはプログラムやシェル)から,別のコマンドを呼び出すということは,プロセスの親子関係を生み出すという行為になる。
ちなみに,「プロセス間の親子関係を断ち切る」のがデーモン。
(例えば Apache Webサーバーのhttpデーモンなど)
デーモンを呼び出すと,自分の子プロセスとはならず,initの子プロセスになる。(後述する。)ただし、子プロセスが設定した環境変数は親プロセスには影響を与えませんし、全く無関係のプロセス(親子の関係にないプロセス)にも反映されません。
常に設定しておきたい環境変数は、.bash_profile などの中で、ログイン時に設定するといいでしょう。
ファンイン、ファンアウトという言葉を初めて知った。
「そういえばAND回路は2入力1出力だから、ファンインが2でファンアウトが1、みたいに言いますね」
合わせて読んだ:
change_column_null
なんてもう忘れた。
null制約のためのマイグレーション用メソッドなので、第3引数をtrueにしたら制約され、falseだとnull制約がなくなる。逆に覚えそうで怖い。
Vite.jsなるものが気になる。
GitHub Copilotのライセンス違反問題がとても気になる。
"Active Recordの「Leaky Abstraction」を削減する"
Controllerでよく使うクエリはModelのクラスメソッドにしようという話。
いろいろ語弊があるかもしれないけど。
byebugからdebugへの移行ガイド。
ざっと読んだだけです。
2023年
雑多ニュース。
ruby-lspについてちょろっと書いてあった。
LSPというのを初めて知った。
今まではsolargraphというgemがあったみたいだが、Shopifyがruby-lspというgemを作ったという話。
ActiveSupport::Inflectorのメソッドをよく忘れるので。
さいごに
Thanks to TechRacho. Your articles are all very practical!!