Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
本当は怖い Rails の `build_xxx` / The Hard Facts of `...
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
megane42
July 30, 2019
Programming
310
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
380
Rails deprecation warning に立ち向かう技術 / v.s. rails deprecation warnings
megane42
0
860
OSS コミットゴルフのすすめ / Let's play OSS-contribute-golf
megane42
0
150
ゆる計算理論ラジオ / P vs NP for beginner
megane42
1
300
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
650
Other Decks in Programming
See All in Programming
全ての永続トークンを、生まれる前に消し去りたい!
sylph01
3
1.7k
プロジェクトコードをキレイキレイしよう!暗黙的な参照を読み解く静的解析
ostk0069
0
200
Materialが消えた日 〜真っ白なFlutterキャンバスにRenderObjectで絵を描く〜
umigishiaoi
0
140
Enforcing Your Architecture with Unit Tests in the AI Era (Swift Connection X)
steliosf
PRO
1
120
Railsバージョンを4倍にした話
optim
0
920
小さなアプリを作って公開するまで
onozaty
0
110
Event is what happens
moro
2
3.4k
S3 TablesのIcebergデータに、AIエージェントからアクセスしてみた / 20261016developersio2026joetsu-accessing-iceberg-in-s3tables-via-agent
kasacchiful
PRO
0
270
AWS CDKを理解するために公式の定義を深掘って解説してみる / Understanding AWS CDK by Digging into Its Official Definition
akihisaikeda
2
200
느린 네트워크와 저사양 디바이스 사용자를 위한 웹뷰 로딩 시간 개선기
kmkim
1
180
FactoryBotをやめればRSpecは速くなるのか?
yuta_onishi_97
0
1.5k
GraphQL の onError と Nullability のこれから
quramy
0
200
Featured
See All Featured
How to build a perfect <img>
jonoalderson
1
6.2k
The Hidden Cost of Media on the Web [PixelPalooza 2025]
tammyeverts
2
560
Exploring anti-patterns in Rails
aemeredith
4
560
Reflections from 52 weeks, 52 projects
jeffersonlam
356
22k
Gemini Prompt Engineering: Practical Techniques for Tangible AI Outcomes
mfonobong
2
620
Leadership Guide Workshop - DevTernity 2021
reverentgeek
1
420
What Being in a Rock Band Can Teach Us About Real World SEO
427marketing
0
1.1k
Measuring & Analyzing Core Web Vitals
bluesmoon
9
1.1k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.7k
Odyssey Design
rkendrick25
PRO
2
920
Money Talks: Using Revenue to Get Sh*t Done
nikkihalliwell
0
550
エンジニアに許された特別な時間の終わり
watany
109
250k
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 も怖かった