- Ruby / Rails関連
週刊Railsウォッチ: 2021年度Rubyアソシエーション開発助成、Rails REST APIレベルで楽観的ロックほか(20211102後編)
こんにちは、hachi8833です。大江戸Ruby会議09 出前Edition、いよいよ今夜ですね。
あしたの夜です!!! "最近の松田明氏による動画アーカイブ発掘調査の結果、過去の RubyKaigi の講演動画を全て発掘することに成功しました。
このたび、この2つの偉業を記念し『大江戸Ruby会議』をオンラインで開催します" https://t.co/LIIe8xiDmd #oedo09— Kakutani Shintaro (@kakutani) November 1, 2021
🔗Ruby
🔗 2021年度Rubyアソシエーション開発助成の結果発表
Rubyアソシエーション開発助成プロジェクトに採択されました。「MRIのWebAssembly対応よるポータブルなRubyプログラムの実現」というのをやっていきます💪
https://t.co/Gp2i7emstI pic.twitter.com/VFN39YfSLF— kateinoigakukun (@kateinoigakukun) October 26, 2021
2021年度Rubyアソシエーション開発助成では、「picoruby-compiler: An alternative mruby-compiler(Monstarlab)」「MRIのWebAssembly対応よるポータブルなRubyプログラムの実現
(齋藤優太)」「“debug.gem”の利用体験・開発効率の改善(小野直人)」「Ruby formatter(Kevin Newton)」が採択されました。おめでとうございます 🎉
つっつきボイス:「今回採択された中に、MRIをスタンドアロンなWebAssembly(Wasm)バイナリにコンパイル可能にするプロジェクトがありました」「おぉ、以前もどなたかがデモしていたのを見たことがありましたが、そのままだと使いにくかったみたいですね: MRIをWasmワンバイナリで配布できるようになったらスゴい」「mrubyはサイズが小さいので以前からWasmで動かせますけどね↓」
MRI (Matz' Ruby Implementation)
C言語で実装されたRubyの公式処理系。すべてのプラットフォームで動作可能。Rubyアソシエーションの理事長である まつもとゆきひろ により開発され始めたもので、最も広く使われている。
http://www.ruby-lang.org/
ruby.or.jpより
🔗 Rubyのメソッド呼び出しでレシーバの有無を判定
つっつきボイス:「この間のKaigi on Rails 2021冒頭のkamipoさんQ&A企画で、kamipoさんが『Active Recordのscoping
を修正するために、"レシーバを付けて呼び出したか付けずに呼び出したかを判定する機能"がRubyに欲しいと思っていた』とお話ししていた↓のを自分も見て、その後で上のアンサー記事が出ました」
参考: Rails API scoping
-- ActiveRecord::Relation
「お〜、private
メソッドの仕組みをうまく使うことでwhere
のレシーバありとなしを判定するとはテクニカル」
# 同記事より抜粋
class User
def self.where
"レシーバなし"
end
def self.where_with_receiver
"レシーバあり"
end
class <<self
private :where
# private メソッドでレシーバありで呼び出された場合に method_missing が呼ばれる
def method_missing(name, *args)
if name === :where
where_with_receiver(*args)
else
super
end
end
end
end
参考: Module#private
(Ruby 3.0.0 リファレンスマニュアル)
🔗 Rubyのハックよもやま
「こういう高度な技を実際に使うとなると、他の人が見たときにコードの意図がわからなくなる可能性はあるかも」「あ〜、それもそうか」「ActiveSupport::Concern
でラップしてそれを使うなどすればよいかもしれませんが」
参考: Rails API ActiveSupport::Concern
「一時期流行ったCSSハックなどもそうですけど、ハック系の技ほどコンテキスト依存が強くなる、つまりハイコンテキストになってしまいがち」「ふむふむ」「Rubyの嬉しい点は『こう書いたら動くかな?』と思って書いたら本当に動くことだと自分は思っているので、あまりハイコンテキストな方向に進まない方が個人的には嬉しいかも」「たしかにこういう状況ではこう書かないと動かないみたいなのはRubyっぽさが下がりそうですね」
参考: CSSハックについて | GRAYCODE HTML&CSS
「kamipoさんの話を聞いたときは、Rubyでもできないことがあるのかと思っちゃいました」「安全その他の理由で言語には何らかの制約があるものなので、できないことはあるでしょうね」
🔗 ブロック内にreturn
を書くとどうなるか(Ruby Weeklyより)
つっつきボイス:「ブロック内でreturn
を書いたときの話ですね: 思わぬ挙動が起きるヤツ」「ここでハマる記事をよく見かけますね」
# 同記事より
def some_method(&block)
block.call
completed = true # won't be called if the block returns early
ensure
if completed
puts "ok"
else
puts "returned early"
end
end
some_method { return } # => "returned early"
some_method { next } # => "ok"
参考: Ruby のブロック内で return すると… - Secret Garden(Instrumental)
「ところがブロック内のreturn
って、とても書きたくなるときがあるんですよ」「おぉ?」「たとえばRSpecのexpectブロックに書く条件が複雑になってくるとif
文が入ってきたりするんですが、Rubyのブロックが返すのは最後に評価された値なので、それを変えたくてreturn
を書いてしまうと、そのブロックが終了するのではなく、そのブロックがあるメソッドそのものが終了する」「そういえばブロックの中に他にも制御文を書けたりしますね」「書けてしまうが故にうっかり書いてしまいがち」
参考: 制御構造 (Ruby 3.0.0 リファレンスマニュアル)
「個人的にはブロックにreturn
を書いたらwarningを出してくれてもいいのにという気持ちになることもあります」「わかります」
🔗 その他Ruby
改訂版に関する情報はこちら。発売日は12月2日に決定しております。もうすぐです!!(なので今がんばってる)
年内に発売?改訂版「プロを目指す人のためのRuby入門」を制作しています! - give IT a try https://t.co/XXtChjvdZ1
— Junichi Ito (伊藤淳一) (@jnchito) October 23, 2021
つっつきボイス:「チェリー本第2版の発売日が決まったんですね」「急遽ruby/debugの解説を加えたそうです」「発売後ひと月しないうちにRuby 3.1が出るのか...」「Ruby 3.1はツールチェインは増えるけど、書き方はあまり変わらないから影響は小さいでしょうね」
以下はつっつき後に見つけたツイートです。後ひと月で販売ですね。
12月2日発売の改訂版「プロを目指す人のためのRuby入門」が予約商品の20位に!まだ表紙画像も公開されてないのに、もう予約してくれたみなさんにマヂ感謝🙏https://t.co/b8nxzz3a3A 新着ランキング: プログラミング の新着ランキングです。 https://t.co/pg5hZum6C1 pic.twitter.com/d608QrlRsY
— Junichi Ito (伊藤淳一) (@jnchito) October 31, 2021
🔗Rails
🔗 RailsのREST APIの楽観的ロック(Ruby Weeklyより)
つっつきボイス:「よくあるデータベースの楽観的/悲観的ロックの話かなと思ったら、よく見るとRailsのREST APIレベルでの楽観的/悲観的ロックの話のようですね」「あ、RESTレベルのロックでしたか😅: DBカテゴリに置いてましたがRailsカテゴリに変えておきます」
参考: 楽観ロック/悲観ロック(optimistic locking/pessimistic locking)とは - IT用語辞典 e-Words
「記事によると、ActiveRecord::Locking::Optimistic
というまさに楽観的ロックのための機能があるらしい」「こんな機能もあったんですね」「そういえばlock_version
カラムがActive Reordで使えるのを思い出した: これを使って行ロックをかけられる」「お〜、lock_version
カラムを追加すればActive Recordの機能だけで使えるんですね」
参考: Rails API ActiveRecord::Locking::Optimistic
Active Recordは、
lock_version
フィールドが存在する場合に楽観的ロックをサポートする。レコードが更新されるたびにlock_version
カラムがインクリメントされる。2回インスタンス化されたレコードは、最後に保存された方が更新されるとStaleObjectError
をraiseする。
api.rubyonrails.orgより
# api.rubyonrails.orgより
p1 = Person.find(1)
p2 = Person.find(1)
p1.first_name = "Michael"
p1.save
p2.first_name = "should fail"
p2.save # Raises an ActiveRecord::StaleObjectError
「元記事では、最終的にHTTPのETagヘッダーをlock_version
と連携させて楽観的ロックを実現しているんですね↓: ensure_if_match_header_provided
メソッドでIf-Match
ヘッダーの存在を確認して、なければHTTP 428を返す、へ〜!」「HTTP 428は、Precondition Required(前提条件が必要)なんですね」「元記事の1つ前のコードは、If-Match
ヘッダーがなくても呼べてしまってHTTP 500(内部エラー)になるので、こう変えたのか」
# 同記事より: 最終的なコード
class RentalsController
before_action :ensure_if_match_header_provided, only: [:update]
after_action :assign_etag, only: [:show, :update]
rescue_from ActiveRecord::StaleObjectError do
head 412
end
def show
@rental = Rental.find(params[:id])
respond_with @rental
end
def update
@rental = Rental.find(params[:id])
@rental.update(rental_params)
respond_with @rental
end
private
def ensure_if_match_header_provided
request.headers["If-Match"].present? or head 428 and return
end
def assign_etag
response.headers["ETag"] = @rental.lock_version
end
def rental_params
params
.require(:rental)
.permit(:some, :permitted, :attributes)
.merge(lock_version: lock_version_from_if_match_header)
end
def lock_version_from_if_match_header
request.headers["If-Match"].to_i
end
end
参考: 428 Precondition Required - HTTP | MDN
参考: 500 Internal Server Error - HTTP | MDN
「REST APIレベルで楽観的ロックをかけるこの書き方はたしかに正当なRESTful、面白い!」
参考: RESTful API(REST API)とは - IT用語辞典 e-Words
🔗 ETagとRESTful
「まだETagがわかっていないんですが、ETagは使わないこともできるんでしょうか?」「ETagはHTTPキャッシュ機構のひとつで、サーバーがETagを付けてレスポンスを返したらクライアントもETagを付けることになっていた気がしますが、ETagはもともとキャッシュのためのものだから、クライアントもETagに対応する義務はあるんだろうか?うん、この記事のような方法でETagを使うことは果たして正当なのかどうかを考えるのは議論として面白いですね」
「MDNを見ると、If-None-Matchをヘッダーに含めることが"できます"と書かれてる↓」「英語版も同じ部分がcanになってますね」「つまりクライアントはETagを無視することも可能ということか」
ETag レスポンスヘッダーは strong validator として使用できる、ユーザーエージェントにとって不透明な値です。ブラウザーなどの HTTP ユーザーエージェントは、この文字列が何を表すかがわからず、またこの値が何になるかを予測することもできません。ETag ヘッダーがリソースのレスポンスの一部に含まれていたら、クライアントは以降のリクエストでキャッシュ済みリソースの確認を行うために If-None-Match をヘッダーに含めることができます。
developer.mozilla.orgより
「今のMDNの説明はIf-None-Matchについてのものだから、元記事で使っているIf-Matchがどうなのかも見てみるか」
「元記事の記述を見ると、この実装はクライアント側がETagのIf-Matchを実装していることを求めていることになりますね↓」「ふむふむ」「もちろんこれがRESTfulであることは変わりませんが」
If-Match
ヘッダーを使えば、APIサーバーはリソース変更の有無を非常に手軽に確認できます。チェックサムやバージョン番号など、その他ETagとして選んだどれでも比較すればよいのです。
同記事より
「RESTfulはなるべくHTTPの機能でやろうという考え方なので、この記事のやり方はRESTfulの解釈のひとつとしてありだと思います👍」「こういうのはRails Wayでもあるんでしょうか?」「RESTfulですが、Rails Wayとは言いにくいかな」「なるほど」「クライアント側での処理を増やしてはいますが、RESTfulという視点ではキレイに決まっているので、Rails WayよりはRESTfulという思想に忠実な実装だと思います」「思想ですかなるほど」
🔗クラウド/コンテナ/インフラ/Serverless
🔗 Cloudflareの機能
つっつきボイス:「CloudflareのArgo Tunnelクライアントを使うとngrokみたいなことができる」「ngrokって、ローカルで起動したサーバーをネット上でいきなり公開できる便利ツールですね↓」「クライアント名はcloudflaredで、基本的にはCloudflare側にトンネリングするツールなのか」
🔌 ngrock is an amazing tool to share localhost urls with teammates or touch devices 👏🏻👏🏻 it made my day, thanks! https://t.co/IddYXq2WVI pic.twitter.com/9yFCUdRQoV
— Quique Fdez Guerra (@CKGrafico) October 27, 2021
「Cloudflare Pagesは初めて知った」「Cloudflareには他にもツールチェイン的な機能がいろいろ増えている感じですね」
以下はつっつき後に見つけたツイートです。
Cloudflare Pages 使ってみてるんだけどこれは現状最つよなのではhttps://t.co/aFEvWvAQoZ
— Takahiro Ikeuchi / UIデザインをするCTO (@iktakahiro) October 31, 2021
後編は以上です。
バックナンバー(2021年度第4四半期)
週刊Railsウォッチ: Rails 7アセットパイプライン解説記事、ロジックをapp/operatorsで整理ほか(20211101前編)
- 20211026後編 YJITがRuby 3.1向けにマージ、ripperのドキュメント化、crontabの罠ほか
- 20211025前編 insert_allやupsert_allのタイムスタンプ自動更新、rails/contextsにロジックを置くほか
- 20211019後編 ruby/debugをChromeでリモートデバッグ、Rubyアプリの最適化ほか
- 20211018前編 Railsリポジトリで進行中のPropshaft、inverse_ofを自動推論ほか
- 20211012後編 Ruby 3.1にYJITマージのプロポーザル、Rubyのmagic historyメソッド、JSのPartytownほか
- 20211011前編 ServerTimingミドルウェア追加、paramsで数値キーを許可、Railsで多要素認証ほか
- 20211006後編 ruby/debug 1.2.0リリース、Railsにはthorが入っている、tendejitほか
- 20211004前編 Rails 7でbyebugがruby/debugに変更、GitHub Codespacesをサポートほか
今週の主なニュースソース
ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSやruby-jp SlackやRedditなど)です。
週刊Railsウォッチについて
TechRachoではRubyやRailsなどの最新情報記事を平日に公開しています。TechRacho記事をいち早くお読みになりたい方はTwitterにて@techrachoのフォローをお願いします。また、タグやカテゴリごとにRSSフィードを購読することもできます(例:週刊Railsウォッチタグ)