- Ruby / Rails関連
週刊Railsウォッチ: RailsでApplication Layer Encryption、rubocop-factory_bot登場ほか(20230614後編)
こんにちは、hachi8833です。
🔗Rails
🔗 has_one
の関連付けでレコードが1つになるとは限らない
つっつきボイス:「thoughtbotの記事です」「has_one
関連付けでレコードがいつも1つだと思ってはいけない?」「レコードが入ってしまえば複数になることはありえますね」
「そうならないためにはこうやってデータベース側に制約を追加する↓」「これならデータベース側で追加を阻止できますね」
# 同記事より
class CreateAccounts < ActiveRecord::Migration[7.0]
def change
create_table :accounts do |t|
t.string :name
- t.belongs_to :supplier, null: false, foreign_key: true
+ t.belongs_to :supplier, null: false, index: { unique: true }, foreign_key: true
t.timestamps
end
end
end
参考: §2.2 has_one
関連付け -- Active Record の関連付け - Railsガイド
🔗 Active Recordのメソッドで式展開を使ってはいけない(Ruby Weeklyより)
つっつきボイス:「これはもう定番の話ですね」「これは場合によってはえらいことになる書き方↓」
# 同記事より: やってはいけない書き方
User.delete_by("id = #{params[:id]}")
User.where("email = #{params[:email]}")
「記事にもあるように、サニタイズされない形でデータをクエリに渡すとSQLインジェクションにやられる可能性がありますね」
# 同記事より: SQLインジェクションの例
# user-provided parameter
params[:id] = "1) OR 1=1--"
User.delete_by("id = #{params[:id]}")
#=> User Delete All (4.2ms) DELETE FROM "users" WHERE (id = 1) OR 1=1--)
「ところでこういう記事を見るとArelを勉強しようという気持ちになってきますね」
🔗 AsherahでRailsのApplication Layer Encryptionを実装する(Ruby Weeklyより)
つっつきボイス:「Application Layer EncryptionをRailsで実装する記事か、面白そう」「asherahというライブラリをasherah-ruby経由で使っているんですね」「asherahを開発したのはドメインレジストラで有名なGoDaddyか: よく見たらこの記事もGoDaddyのサイトだった」
Asherahは、Go版のAsherah Application Layer Encryption SDKをRuby FFI(外部関数インターフェイス)でラップしたものです。Asherahは、高度な暗号化機能や、侵害に対する深層防御を提供します。「エンベロープ暗号化」と呼ばれる技術を利用して、クラウドに依存しないデータストレージと鍵の管理をサポートします。
github.com/godaddy/asherah-ruby READMEより
参考: AWS KMS の概要とエンベロープ暗号化について説明してみる - 私の戦闘力は53万です
「この図がわかりやすい↓: 記事によるとマスターキー(MK)としてKMSの他にハードウェアセキュリティモジュール(HSM)も使えるとあるので、本格的な機能のようですね」「図の最上位の赤いキーがマスターキーで、その下のメタストア層の中間キーがこのライブラリで管理されるんですね」「通常の暗号化は1つのキーを使うけど、この方法だと最下層の永続化層にあるデータ行はその上のすべてのキーが揃って初めてアクセスできるんでしょうね」「メモリダンプでデータを取り出せないようにメモリ上のデータも保護されるのか」
同記事より
「asherahの設定ファイル↓を見ると、config.metastore
にrdbmsを指定したりできるらしい: 記事をざっと眺めただけでも興味を惹かれる技術ですね👍」
# 同記事より
Asherah.configure do |config|
config.service_name = 'marketing'
config.product_id = 'email'
config.metastore = 'rdbms'
config.enable_session_caching = true # default: false
c = ActiveRecord::Base.connection_db_config.configuration_hash
config.connection_string = "#{c[:username]}:#{c[:password]}@tcp(#{c[:host]}:#{c[:port]})/#{c[:database]}"
if ENV['ASHERAH_KMS_ENABLED'] == 'true'
config.kms = 'aws'
config.preferred_region = ENV.fetch('AWS_REGION')
config.region_map = { ENV.fetch('AWS_REGION') => ENV.fetch('KMS_KEY_ARN') }
elsif Rails.env.development? || Rails.env.test?
config.kms = 'static' # The static key used for encryption is `thisIsAStaticMasterKeyForTesting` (defined in Asherah Go)
else
raise "Asherah client not configured for: #{Rails.env}"
end
end
🔗 rubocop-factory_bot(Ruby Weeklyより)
つっつきボイス:「factoryの作り方は人によってかなり癖があったりするので、factory_bot向けのRuboCopがあってもよさそう👍」「ドキュメントを見ると、既にいろいろなcopがあるんですね」
参考: FactoryBot :: RuboCop Docs
# docs.rubocop.orgより: FactoryBot/CreateList
# bad
3.times { create :user }
3.times.map { create :user }
[create(:user), create(:user), create(:user)]
Array.new(3) { create :user }
# good
create_list :user, 3
# bad
3.times { create :user, age: 18 }
# good - index is used to alter the created models attributes
3.times { |n| create :user, age: n }
# good - contains a method call, may return different values
3.times { create :user, age: rand }
🔗Ruby
🔗 contracts.ruby: Rubyで契約プログラミング
参考: Contracts.ruby by egonSchiele -- チュートリアル
つっつきボイス:「以下のツイートで探してみてcontracts.rubyを見つけました」
Contracts も加えてやってほしい https://t.co/HYwzLk1W37 / https://t.co/wWzGZ5ltGf
— wtnabe, yet another yak shaver (@wtnabe) June 6, 2023
「Contract Num => Num
みたいな感じで型を定義すると、違う型の値を渡したときにエラーを出すもののようですね: コード内に書くところはSorbet的」「★が1400超えていて、"メンテナー募集"とありますね」「コミットはそこそこ動いているけどissuesはあまり動いてないっぽい: 本番でヘビーに使うというより、参考になったという意味での★なのかもしれませんね」
# 同リポジトリより
require 'contracts'
class Example
include Contracts::Core
include Contracts::Builtin
Contract Num => Num
def double(x)
x * 2
end
end
puts Example.new.double("oops")
「このgemは知らなかったけど、contractはいわゆる契約プログラミングのようですね: とりあえずWikipediaを見ると、クライアントの事前条件遵守やサプライヤの事後条件遵守のあたりが契約に相当するんでしょうね↓」「動作としては実行時チェックっぽいですね」
契約はまたクライアントとサプライヤに生じる義務と利益によって特徴付けられる。 クライアントの設計者にはクラスのインタフェースとして示された事前条件を遵守する義務が生じる一方、事後条件が満たされること期待してよく、反対にサプライヤの設計者はクライアントが事前条件を満たしてクラスを利用することを期待してよい一方、事後条件を遵守する義務が生じる。 このクライアントとサプライヤの双方に生じる義務と、義務を守った際に保証された状態を得られる利益とが現れる点で、プログラミングにおける「契約」と一般的な意味での契約の類似を見出せる。
契約プログラミング - Wikipediaより
🔗 Rubyで列挙型(enum)っぽく連番を定義できるgemを作ってみた
Qiita記事書きました。「Rubyでも列挙型が使えたらいいのに!」って思うときが、たま〜にあるので、「あったらいいな」をgemにしてみました。
Rubyで列挙型(enum)っぽく連番を定義できるgemを作ってみた https://t.co/h4NbrzFHLD
— Junichi Ito (伊藤淳一) (@jnchito) June 6, 2023
つっつきボイス:「jnchitoさんの記事です」「C言語のenum型みたいなものをRubyでやってみたくなる気持ちわかる: 普通のRubyだとこういうことをするためにハッシュを作ったりしますね」
# 同記事より
require 'seq_as_enum'
class Sample
extend SeqAsEnum
# seq_as_enumメソッドで連番を定義
seq_as_enum :RED, :YELLOW, :GREEN
# すると、以下のような定数が定義される
# RED = 0
# YELLOW = 1
# GREEN = 2
# 上で定義した連番を使用する
def self.main
puts "RED = #{RED}"
puts "YELLOW = #{YELLOW}"
puts "GREEN = #{GREEN}"
end
end
Sample.main
「こういうふうに連番を割り当てる方法はメタプログラミングと相性が悪いんですよ: メタプロによるパッチ当てでenum値の種類を増やしたり減らしたりするようなコードがあると期待通りに動かないといったケースもあり得るので、Ruby本体の機能としてenum連番が必要かどうかについては微妙なところかもしれません」
🔗 RubyKaigi 2023で興味を持った技術
【Ruby】RubyKaigi2023で興味を持った技術 https://t.co/I5CPVoEiBg #Ruby #RubyKaigi #RubyKaigi2023
— かみくだく🇺🇦🤝🇷🇺🤝🇹🇼🤝🇨🇳 (@kamikudakun) June 7, 2023
つっつきボイス:「RubyKaigi 2023の報告記事もだいぶ増えてきましたね」「Scrapboxのまとめを見るとかなりの数になってます↓」
🔗 設計
🔗 日本の住所
つっつきボイス:「上の記事がバズってますね」「経済産業省の公式APIがあるといっても住所の正規化はまだまだ大変そう(ウォッチ20200601)」
「関連する記事をいくつか見繕いました: 京都の通り名が厄介なのは有名ですけど、北海道の住所も手強い」
- 元記事: 京都の通り名(住所雑学シリーズ12) | 株式会社エニイ
- 元記事: 独特の住所表示「条丁目」街区が北海道にこんなにある理由│北海道ファンマガジン
- 元記事: 君が知らない石川県の珍地名。 〜google mapでブラ・モリ〜 | タマノモリ
住所の正規化がいかに難しいかで盛り上がっていて、なんか嬉しい😊
住所関連の開発、個人的にもかなり長い時間をかけたのですが、一番ヤバいと思ったのは・新潟県新潟市北区東栄町(とうえいちょう)
・新潟県新潟市北区東栄町(ひがしさかえまち)という2つの「異なる」地域が存在することです。
— choo (@choo_s) June 6, 2023
「住所という概念がない国...」
まず郵便物は国によって異なりますが
「郵便局や受け渡し場所が指定される」つまり自分から取りに行く国も多かったりします。
例えば郵便局の私書箱とか勤務先のポストとか。日本じゃ信じがたいですけどね。
おかげで日本と違い「再配達」なんて
概念自身そもそもないですけどね。(続く2
— Joji Cokumu(狐アイコン唯一の良心。モフモフしたい。赤字貿易経営者!毒の人ではありません) (@_596_) June 7, 2023
なお、番地と住所については以下の本がおすすめです。著者の今尾恵介さんは他にも地図や住所に関する本をたくさん出しています。
🔗クラウド/コンテナ/インフラ/Serverless
🔗 AWS LambdaがRuby 3.2をサポート
AWS ラムダがルビー3.2のサポートを追加。
AWS Lambda は、マネージドランタイムとコンテナベースイメージの両方として Ruby 3.2 をサポートするようになりました。Ruby 3.2 を使用して Lambda でサーバーレスアプリケ...(1/3) https://t.co/UFq9uiHscl
— What's New on AWS (非公式) (@awswhatsnew_jp) June 7, 2023
つっつきボイス:「LambdaでRuby 3.2がサポートされた🎉」「最新なのがありがたい」「Lambdaランタイムのサポートリストを見ると前のバージョンはRuby 2.7なのか」「だいぶジャンプしましたね」「LambdaでRubyを積極的に使っている人って少ないんだろうか🤔」「ところでツイートで"ルビー"になってるあたり、いかにも機械翻訳っぽいですね」
後編は以上です。
バックナンバー(2023年度第2四半期)
週刊Railsウォッチ: Arel::Nodes::Cteが追加、html_escape_onceの修正ほか(20230613前編)
- 20230608後編 Jets v4リリース、頑張らない型導入、Rust言語からCrabがforkほか
- 20230607前編 MessagePackがcookieシリアライザとメッセージシリアライザにも導入ほか
- 20230531後編Rubyで環境変数を扱う、Web標準に「Baseline」ステータス追加ほか
- 20230525後編 Ruby 3.3.0-preview1リリース、in_order_ofのバグ修正ほか
- 20230524前編 withで作成したリレーションをjoinsで指定可能に、キャッシュストアの例外処理を統一ほか
- 20230502 スライド『Rails 7.1をn倍速くした話』、Rails 7.1でMessagePackをサポートほか
- 20230427後編 第1回Rails Worldが10月に開催、『研鑽Rubyプログラミング』でRuby本体も高速化ほか
- 20230425前編 Rails 7.1の複合主キー対応が引き続き進む、exceptメソッドにwithoutエイリアスが追加ほか
- 20230413後編 ShopifyのRubyパーサーyarp、RJITを書いた理由ほか
- 20230412前編 複合主キーの実装が進む、Rails公式のバグ再現用テンプレートほか
- 20230406後編 Rubyオブジェクトモデルクイズの最難問ほか
- 20230405前編 Arel::Nodes::NodeにAPIドキュメントが追加、rubocop-mdほか
ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSやruby-jp SlackやRedditなど)です。
週刊Railsウォッチについて
TechRachoではRubyやRailsなどの最新情報記事を平日に公開しています。TechRacho記事をいち早くお読みになりたい方はTwitterにて@techrachoのフォローをお願いします。また、タグやカテゴリごとにRSSフィードを購読することもできます(例:週刊Railsウォッチタグ)