Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
本当は怖い Rails の `build_xxx` / The Hard Facts of `...
Search
megane42
July 30, 2019
Programming
290
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
本当は怖い Rails の `build_xxx` / The Hard Facts of `build_xxx` of Rails
megane42
July 30, 2019
More Decks by megane42
See All by megane42
Immutable ActiveRecord
megane42
0
360
Rails deprecation warning に立ち向かう技術 / v.s. rails deprecation warnings
megane42
0
830
OSS コミットゴルフのすすめ / Let's play OSS-contribute-golf
megane42
0
140
ゆる計算理論ラジオ / P vs NP for beginner
megane42
1
290
How to Make "DJ giftee"
megane42
1
1k
Rails 6 Upgrade "Practical" Guide
megane42
6
1.4k
updated_at に依存したら大変なことになった / Don't depend on updated_at
megane42
0
640
Other Decks in Programming
See All in Programming
わからない話を追いかけたら、プログラミング言語を作る側にいた
ydah
3
560
30年振りにコンパイラの定数整数除算を改善した
herumi
9
4.3k
Webエンジニアなのにブラウザの仕組みがわからないので、Pythonで自作してみた
tatsuki12
4
1.1k
リアルな遅延を測る仕様
kota_yata
1
130
Jindong: Introducing Declarative Haptics in Compose Multiplatform
l2hyunwoo
0
130
「つくるAI」だけではバグは見つからない ~テストに必要な「見つけるAI」を分離させる戦略~
mfunaki
0
200
仕様駆動開発へのトライを機に チームに適合する手法を模索し続けている話
freee
PRO
0
650
生成AIで帳票OCRが「簡単に」作れる時代になった?
kon_shou
0
1.2k
コンパウンドプロダクト開発のためのローカルプロセスマネージャー再発明 #layerxgo
izumin5210
0
460
AI Engineeringは、AIプロダクトだけのものか? 〜AIがソフトウェアを作る時代の新しい当たり前〜 / No AI in your product. AI Engineering in your development.
rkaga
5
550
源内ハンズオン概要編
hideg
0
220
私のClaude Code活用法 (個人開発編) - PHPerKaigi mini #4(2026/08/24)
panda_program
1
190
Featured
See All Featured
Heart Work Chapter 1 - Part 1
lfama
PRO
8
36k
The Director’s Chair: Orchestrating AI for Truly Effective Learning
tmiket
1
290
Un-Boring Meetings
codingconduct
0
400
Leveraging Curiosity to Care for An Aging Population
cassininazir
1
480
How Fast Is Fast Enough? [PerfNow 2025]
tammyeverts
3
830
Discover your Explorer Soul
emna__ayadi
2
1.3k
SEO Brein meetup: CTRL+C is not how to scale international SEO
lindahogenes
1
2.8k
Kristin Tynski - Automating Marketing Tasks With AI
techseoconnect
PRO
0
480
The Power of CSS Pseudo Elements
geoffreycrofte
82
6.5k
SEOcharity - Dark patterns in SEO and UX: How to avoid them and build a more ethical web
sarafernandez
0
260
We Analyzed 250 Million AI Search Results: Here's What I Found
joshbly
1
1.9k
職位にかかわらず全員がリーダーシップを発揮するチーム作り / Building a team where everyone can demonstrate leadership regardless of position
madoxten
65
57k
Transcript
本当は怖い Rails の build_xxx @ giftee tech bash #2 (2019‑07‑30)
kazama (@megane42) Solution dev. GCP
概要 Rails の build_xxx 系のメソッドが怖かったという話をします
今日の登場人物(モデル) User Blog user has_one blog
お題 ある user の持ち物としての blog インスタンスを作りたい
方法 create_xxx インスタンスを作って DB に即保存 user.create_blog(title: "foo", ...) build_xxx インスタンスは作るけど
DB に保存はしない 今日の主役 user.build_blog(title: "foo", ...)
疑問 has_one だけど何度も繰り返したらどうなるの?
create の場合 まず新しい blog レコードを保存 次に古い blog レコードの外部キー (user_id) を
null にする dependent: :destroy のときはここが DELETE になる 結果的に子レコードは 1 つに保たれるので、まあわかる # 2 回目の user.create_blog を実行したときの SQL begin transaction INSERT INTO "blogs" ("user_id", "created_at", "updated_at" commit transaction begin transaction UPDATE "blogs" SET "user_id" = ?, "updated_at" = ? WHERE commit transaction
build の場合 # 1 回目 blog = user.build_blog blog.save #
2 回目 blog = user.build_blog さて何が起きるでしょう?
None
結果 まさかの 更新系 が走る dependent: :destroy の場合は DELETE が走る! このあと結局
blog.save をしなかった場合 or 失敗した場合、当 然旧レコードは更新されっぱなしのまま build_xxx は DB を更新しない、という直感に反している # 2 回目の blog = user.build_blog を実行したときの SQL begin transaction UPDATE "blogs" SET "user_id" = ?, "updated_at" = ? WHERE commit transaction
対策 new を使う build_xxx まで含めてトランザクションを張る build_xxx が更新系を実行しうる、という認識を持っておく transaction do blog
= user.build_blog blog.some_operation blog.save end
余談 : ドキュメントにはどう書いてある? Account#build_beneficiary (similar to Beneficiary.new(account_id: id) ) シミラートゥー(イコールとは言ってない)
https://api.rubyonrails.org/classes/ActiveRecord/Associations/Cla ssMethods.html#method‑i‑has_one
余談 : create_xxx も怖くね? なぜか トランザクションが分かれている INSERT 後の UPDATE or
DELETE に失敗するとゴミレコードが残る 例えば belongs_to: に optional: true を付け忘れると UPDATE に失敗する これもトランザクション張った方がいいのかも? # 2 回目の user.create_blog を実行したときの SQL (再掲) begin transaction INSERT INTO "blogs" ("user_id", "created_at", "updated_at" commit transaction begin transaction UPDATE "blogs" SET "user_id" = ?, "updated_at" = ? WHERE commit transaction
まとめ build_xxx は 更新系 を発行しうる create_xxx も怖かった