- Ruby / Rails関連
週刊Railsウォッチ(20210330後編)Active Recordモデル属性暗号化が標準で入る可能性、Flipper Cloud、awesome_printほか
こんにちは、hachi8833です。
🔗Rails: 先週の改修(Rails公式ニュースより)
今週は以下のコミットリストのChangelogを中心に見繕いました。
🔗 RemoteIPミドルウェアでtrusted_proxies
に単独の値代入を非推奨化
- PR: Deprecate assigning single `trusted_proxies` value by csutter · Pull Request #40789 · rails/rails
つっつきボイス:「app.config.action_dispatch.trusted_proxies
に渡すIPアドレスは単独でも配列でも渡せるけど、前者を非推奨化したということのようですね↓」
# 同PRより
# Adds 4.2.42.0/24 to default list of trusted proxies
app.config.action_dispatch.trusted_proxies = IPAddr.new("4.2.42.0/24")
# Replaces default list of trusted proxies with 4.2.42.0/24
app.config.action_dispatch.trusted_proxies = [IPAddr.new("4.2.42.0/24")]
「RackミドルウェアのRemoteIp
のtrusted_proxies
は、たとえばRailsの手前にリバースプロキシを置いてある場合、リクエストの流れがリバースプロキシ->Railsアプリの場合はレスポンスを返すけど、リバースプロキシ以外の怪しいIPアドレスからRailsアプリにリクエストが来た場合はレスポンスを返さないようにするのに使ったりします(IP Spoofing対策)」「あ、そうやって使うんですね」
「こうした制約をインフラレベルだけでかけられれば理想なんですが、CDNなどの制約が絡んだりしてインフラが複雑になると穴を塞ぐのが大変になるので、そういうときにtrusted_proxies
を使うことがあります」
参考: コンテンツデリバリネットワーク - Wikipedia
「trusted_proxies
に配列を渡せるなら単独の値もカバーできるけど、単独の値を非推奨化する必要はあるのかな?🤔」「まだしばらくは単独の値も使えそう」「今後はenumerableな値を渡せば大丈夫ですね」
🔗 個別のテストファイル実行でパラレルテストが無効になった
つっつきボイス:「bin/test test/controller/parameters/accessors_test.rb
のようにファイルを1個だけ指定する場合はパラレルテストをオフにするようになったのか: たしかに1ファイルだけのテストでパラレルテストのワーカーをセットアップするのは完全に無駄ですね」「たしかに」「IDEの保存時実行機能やguard gemなどを使って保存ファイルだけテストを自動実行するのが速くなりそう👍」
# 改修前
actionpack $ bin/test test/controller/parameters/accessors_test.rb
Run options: --seed 48261
........................................................................
Finished in 0.211923s, 339.7460 runs/s, 552.0873 assertions/s.
72 runs, 117 assertions, 0 failures, 0 errors, 0 skips
# 改修後
actionpack $ bin/test test/controller/parameters/accessors_test.rb
Run options: --seed 5461
........................................................................
Finished in 0.008411s, 8560.2189 runs/s, 13910.3557 assertions/s.
72 runs, 117 assertions, 0 failures, 0 errors, 0 skips
🔗 strict_loading!
にn_plus_one_only
モードが追加
- PR: Add n_plus_one_only mode to Core#strict_loading! by dinahshi · Pull Request #41704 · rails/rails
つっつきボイス:「ビックリマーク付きのstrict_loading!
にn_plus_one_only
オプションが入ったそうです」「Changelogの方が見やすそう↓」
- レコードレベルの
strict_loading!
にモード引数を追加
この引数は、単一レコードに対してstrict loadingを有効にし、N+1クエリに対してのみエラーをraiseできる。
developer.strict_loading!(mode: :n_plus_one_only)
developer.projects.to_a # Does not raise
developer.projects.first.client # Raises StrictLoadingViolationError
従来はstrict loadingを有効にすると、lazy loadされたすべての関連付けでエラーがraiseされた。
n_plus_one_only
モードを指定すると、単一のクエリでフェッチされたbelongs_to
やhas_many
などの関連付けをlazy loadできる。
Dinah Shi
同Changelogより大意
「n_plus_one_only
を有効にすると、N+1問題が発生していないとき(レコードを1件だけ読み込む場合)なら関連付けをlazy loadingできて、N+1問題が発生している場合だけエラーをraiseするようになったということのようですね: strict loadingはN+1クエリ問題が発生しないときに行いたいことが多いし、N+1が発生したときはstrict loadingのところで止めたくなると思うので、これが欲しい気持ちはわかります」「なるほど」「n_plus_one_only
モードは自分的にはなかなか実用的な印象👍」
- Rails API:
strict_loading!
-- ActiveRecord::Core
レコードをstrict_loadingモードに設定する。レコードが関連付けをlazy loadingしようとするとエラーをraiseする。
user = User.first
user.strict_loading!
user.comments.to_a
=> ActiveRecord::StrictLoadingViolationError
api.rubyonrails.orgより大意
🔗 Enumerable#in_order_of
が追加
ActiveRecord::Base#find
は、引数として使われている主キーの順でレコードを返す。これはindex_by
とmap
の合せ技で、#find
以外でも有用。このプルリクはそのパターンをEnumerable#in_order_of
に切り出したもの。
同PRより大意
つっつきボイス:「これは今年2月にマージされたので少し前のPRですが、DHH自らによるものでした」「Active Supportに入ったんですね」「このコードサンプルがわかりやすいかな↓: [1, 5, 3]
を渡すと、id
を持つものをその順序で返す」「あ、なるほど」
# [ Person.find(5), Person.find(3), Person.find(1) ].in_order_of(:id, [ 1, 5, 3 ])
# => [ Person.find(1), Person.find(5), Person.find(3) ]
「Enumerableに追加されたのがいいですね」「順序を指定せずに取りたいことの方が多いと思うけど、このメソッドがあることを知っていれば順序を指定して取りたい場合に使うかも」
# activesupport/lib/active_support/core_ext/enumerable.rb#L194
+ def in_order_of(key, series)
+ index_by(&key).values_at(*series).compact
+ end
🔗 (マージ前)Active Recordモデルの属性を暗号化する機能(Ruby Weeklyより)
つっつきボイス:「現時点(2021/03/25夜)ではまだマージされていませんが、Ruby Weeklyで取り上げられていました」「おぉ、属性の暗号化がついにRailsに統合されそう?」
# 同PRより
class Person < ApplicationRecord
encrypts :name
end
「Action TextやActive Recordなどにも変更が入っている」「よく見たら更新ファイルが82個もあるんですね」「変更多いな〜」「これまでなかった機能が丸ごと入ったから変更量は多いでしょうね」
「Active Record属性の暗号化といえばattr_encrypted gemがかなり昔からよく使われています↓」「そうそう」「GitLabでもattr_encryptedを使っていたと思います」「類似のlockboxやvault-railsもプルリクメッセージで紹介されていますね↓」
「しかもこれはBasecampがやっているHEYのコードから切り出したそうですよ↓」「お〜」「HEYで実績を積んでいるコードが使われているのはありがたい」「encryptorもちゃんと独自に指定できる: これはないと困る機能」「HEYを立ち上げる前にセキュリティファームがこのライブラリをレビューしたと書かれていますね」
# 同PRより
config.active_record.encryption.encryptor = MyEncryptor.new
「属性暗号化機能は多くのアプリで使われるので、Rails標準で入っていてもいい気がしますね」「今どきのフルスタックWebフレームワークなら入っていてもおかしくないかも」「"いいね"もすごくたくさん付いてますね」「これはRailsにあっていい機能👍」「Rails 7にこれが入るなら目玉機能になるでしょうね」
本日(2021/03/30夕方)時点ではまだマージされていません。
🔗Rails
🔗 authorizationのつらみをFlipper Cloudで軽減する(Ruby Weeklyより)
- 元記事: Rails: How to Reduce Friction at the Authorization Layer
- サイト: Flipper Cloud - Feature Flags for Ruby
ICYM, we’re live! Head over to https://t.co/hlv4V2ii18 and sign up today. Kick the tires. We love feedback. pic.twitter.com/BM5yHml6K3
— Flipper Cloud (@flipper_cloud) January 15, 2021
つっつきボイス:「上のFlipper Cloudというサービスを推している記事のようです」「サイトを見た感じでは、いわゆるフィーチャーフラグをクラウドベースで管理できるオープンソースのサービスということらしい」
「gemも公開されている↓:gemでやる場合は自分たちで管理する必要があると思いますが」「設定はIRBでもFlipper::UI
でもできるとありますね」
「コードはフィーチャーフラグそのものという感じなので↓、シンプルなフィーチャーフラグの実装に使えそうかな」「おぉ」
# 同リポジトリより
require 'flipper'
# check if search is enabled
if Flipper.enabled?(:search)
puts 'Search away!'
else
puts 'No search for you!'
end
puts 'Enabling Search...'
Flipper.enable(:search)
# check if search is enabled
if Flipper.enabled?(:search)
puts 'Search away!'
else
puts 'No search for you!'
end
「眺めた限りでは、リポジトリの★も多いし、フィーチャーのオンオフとかも含めて割とよくできていそうな予感がしますね: 興味があれば調査してみてもいいかも」
「元記事の方は、たとえばこれはよくあるポリシー型の権限管理ですね↓」「Flipper Cloudはユーザーごとの権限管理までやれそうに見える」
# 同記事より
class TokenPolicy < ApplicationPolicy
def show?
project_member?
end
def update?
project_member?
end
def destroy?
project_member?
end
private
def project_member?
record.project.member?(user)
end
end
「URLエンドポイントレベルのシンプルな権限管理ならこうしたgemやサービスでやれると思いますが、エンティティレベルで権限管理をしようとするとおそらくpunditのようなものが必要になってくるでしょうね」「なるほど」「そこにGraphQLが絡むとさらに複雑になるんですよ」
「ところで、記事ではmemoistというgemも紹介されていますね↓」「サンプルコードのとおり、いわゆるメモ化を簡単に行えるようですね」「今はRailsからなくなったActiveSupport::Memoizable
から切り出したらしい」「ポリシーは実行中に変えないのが普通なので、記事ではこれでメモ化して高速化を図っているんでしょうね」
# matthewrudy/memoistより
require 'memoist'
class Person
extend Memoist
def social_security
puts "execute!"
decrypt_social_security
end
memoize :social_security
end
person = Person.new
person.social_security
# execute!
# => (returns decrypt_social_security)
person.social_security
# => (returns the memoized value)
参考: メモ化 - Wikipedia
🔗 sqldef: 冪等なスキーマ管理ツール
Goで書かれています。
つっつきボイス:「k0kubunさんの上の記事でsqldefを知りました」「ridgepoleのオルタナ的なツールをk0kubunさんが自分で作ったんですね」「スキーマ管理をSQLで書けるというツールなのか: そういえばずっと前に見たことがあったかも」「実はだいぶ前のウォッチで取り上げてたんですが、ridgepole的なツールとは気づきませんでした(ウォッチ20191119)」
「スキーマ管理をSQLで書きたいor書く必要がある場合にいいかも: たとえばプロジェクト横断的な案件で、Railsでないシステムのデータベースをリードオンリーで共有している場合を考えると、RailsのマイグレーションはRubyがないと動かないのでRubyをインストールするなどの対応が必要ですが、こうやってSQLで書けるならそういう場合に便利かもしれませんね」「ちょうどk0kubunさんの記事の脚注にもそのことが書かれていたので引用しました↓」「そうそう、こういうふうに非Railsプロジェクトとデータベーススキーマを共有したいとか、Railsを知らない人がスキーマ管理するときなどに使えそう」
元々ActiveRecordが入っているRailsだとRidgepoleを使わない理由はほとんどない気がするけど、同じDBをActiveRecord以外からも読むので素のSQLで管理されてる方が扱いやすい (今回のアプリがそれ) とか、DDLは覚えてるけどActiveRecordのDSLは調べないとわからないというようなニッチな用途には便利かもしれない。
同記事脚注より
以下のスライドでもsqldefが取り上げられているのを見つけました。
🔗Ruby
🔗 dead_end: end
の対応関係の誤りを検出する(Ruby Weeklyより)
つっつきボイス:「end
の誤りを検出するという、よくある感じのgemですが、このdead_endという名前がいいですね👍」「ネーミングセンスが光ってる」「RubyMineなどのIDEもやれますけどね」
# 同リポジトリより: endが足りない場合
class Dog
def bark
puts "bark"
def woof
puts "woof"
end
end
# => scratch.rb:8: syntax error, unexpected end-of-input, expecting `end'
# 同リポジトリより: endが余分な場合
class Dog
def speak
@sounds.each |sound| # Note the missing `do` here
puts sound
end
end
end
# => scratch.rb:7: syntax error, unexpected `end', expecting end-of-input
🔗 シェルのディレクトリ一括作成
つっつきボイス:「koicさんのRuboCop記事でシェルの話が載っていました」「mkdir {a,z}
は当然できるけど、mkdir {a..c}
やmkdir {1..10}
でディレクトリを一括作成できるとは知らなかった」「これ初めて見ました」「そういえばシェルに..
記法があったのを今思い出した」「最近シェルスクリプト書いてないな〜😅」
# 同記事より
% mkdir {a,z}
% ls
a z
% mkdir {a..c}
% ls
a b c
% mkdir {1..10}
% ls
1 10 2 3 4 5 6 7 8 9
% mkdir {01..10}
% ls
01 02 03 04 05 06 07 08 09 10
「そして{}
が空だと{}
というディレクトリができてしまう、たしかに」
「そういえばシェルのtest
コマンドに[
という別名がありますよね」「あ〜、ありますあります」「あれを最初知ったときはびっくりしましたけど、わかってみるとシェルすごいかもという気持ちになりますね」「人によりそうですけどね😆」
参考: test と [ と [[ コマンドの違い - 拡張 POSIX シェルスクリプト Advent Calendar 2013 - ダメ出し Blog
🔗 awesome_printが強くなって帰ってきた(Ruby Weeklyより)
つっつきボイス:「awesome_printは、以前は色付けに使うgemという印象でしたが、知らないうちにいろいろ機能が足されているようです」「お〜、オプションがずいぶん増えてますね」
「こういう感じで表示できるのはいい↓👍」「いいな〜」
# 同リポジトリより
$ rails console
rails> require "awesome_print"
rails> ap Account.limit(2).all
[
[0] #<Account:0x1033220b8> {
:id => 1,
:user_id => 5,
:assigned_to => 7,
:name => "Hayes-DuBuque",
:access => "Public",
:website => "http://www.hayesdubuque.com",
:toll_free_phone => "1-800-932-6571",
:phone => "(111)549-5002",
:fax => "(349)415-2266",
:deleted_at => nil,
:created_at => Sat, 06 Mar 2010 09:46:10 UTC +00:00,
:updated_at => Sat, 06 Mar 2010 16:33:10 UTC +00:00,
:email => "info@hayesdubuque.com",
:background_info => nil
},
[1] #<Account:0x103321ff0> {
:id => 2,
:user_id => 4,
:assigned_to => 4,
:name => "Ziemann-Streich",
:access => "Public",
:website => "http://www.ziemannstreich.com",
:toll_free_phone => "1-800-871-0619",
:phone => "(042)056-1534",
:fax => "(106)017-8792",
:deleted_at => nil,
:created_at => Tue, 09 Feb 2010 13:32:10 UTC +00:00,
:updated_at => Tue, 09 Feb 2010 20:05:01 UTC +00:00,
:email => "info@ziemannstreich.com",
:background_info => nil
}
]
「リポジトリにcodeclimate.ymlが置かれている: ちなみにCode Climateは自動コードレビューなどが使えるサービスです」「Code Climateの設定はこういう感じで書くんですね」
「こういうgemが環境に入っていて使えたら嬉しいけど、ただGemfileには書いて欲しくない気持ちがあります」「あ、それわかります」「このgemならrequireに書いてもいいぐらい好きですけど、Gemfileのdevelopmentブロックにgemをいっぱい足すのはあまり好みではないんですよ」「たしかに」
🔗 AWS SDK RubyでRuby 2.2以前のランタイムサポートが終了
つっつきボイス:「お、サポート終了のお知らせか」「ここにリストされているバージョンならRubyソースコードも更新されなくなっていますし、影響はそんなにないと思いますね」
- Ruby 1.9.3 – EOL began on 2015-02-23
- Ruby 2.0.0 – EOL began on 2016-02-24
- Ruby 2.1 – EOL began on 2017-03-31
- Ruby 2.2 – EOL began on 2018-03-31
aws.amazon.comより
後編は以上です。
バックナンバー(2021年度第1四半期)
週刊Railsウォッチ(20210329前編)特集: Rails更新版の臨時リリースとmimemagic gemのGPL問題
- 20210323後編 GitHub Actionsで使えるruby/setup-ruby、中高生国際Rubyプログラミングコンテスト2020ほか
- 20210322前編 Active Recordのstrict loadingの修正、セキュリティリリースのポリシー追加、N+1チェッカーprosopite gemほか
- 20210316後編 testdouble/standard gem、DockerfileベストプラクティスとDockerfileのlintツールhadolintほか
- 20210315前編 Active Recordのenum関連改修、Active SupportのEnumerableでpluckが使えるほか
- 20210309後編 RubyのIRBに隠れているイースターエッグ、Power Automate Desktop、SQLクエリのありがちなミス6つほか
- 20210303後編 Bundlerのセキュリティ修正、Rubyのガベージコレクション記事、Rubyが2/24に誕生日ほか
- 20210222 ActiveRecord::Relationの新メソッドload_asyncとexcluding、Active Jobのperform_laterの改善ほか
- 20210209後編 Rubyでミニ言語処理系を作る、Kernel#getsの意外な機能、CSSのcontent-visibilityほか
- 20210208前編 Rails次期リリースがバージョン7に決定、thoughtbotのアプリケーションセキュリティガイドほか](/hachi8833/2021_02_08/103801)
- 20210202後編 Ruby 3 irbのmeasureコマンド、テストを関数型言語のマインドセットで考えるほか
- 20210201前編 Webpackerのガイドがマージ、RailsはRuby 3でどのぐらい速くなったかほか
- 20210126後編 Google Cloud FunctionsがRubyをサポート、Ruby 3のパターンマッチングでポーカーゲームほか
- 20210125前編 Railsリポジトリのデフォルトブランチがmainに変更、Rails 6.1はMySQLのENUM型に対応済みほか
- 20210120後編 Ruby 3.0の新機能で遊ぶ、RubyスニペットをJSに変換するRuby2JS、rspec-parameterized gemほか
- 20210113後編 Ruby 3.0 Ractor解説記事、Vercelホスティングサービス、教育用OS xv6ほか
- 20210112前編 Active Recordの範囲指定バリデーション改善、soleとfind_sole_byメソッド、AlgoliaとRailsほか
今週の主なニュースソース
ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSやruby-jp SlackやRedditなど)です。
週刊Railsウォッチについて
TechRachoではRubyやRailsなどの最新情報記事を平日に公開しています。TechRacho記事をいち早くお読みになりたい方はTwitterにて@techrachoのフォローをお願いします。また、タグやカテゴリごとにRSSフィードを購読することもできます(例:週刊Railsウォッチタグ)