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
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
megane42
July 30, 2019
Programming
300
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
370
Rails deprecation warning に立ち向かう技術 / v.s. rails deprecation warnings
megane42
0
850
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
モデルのリファクタリングが難しいと思ったら、そもそも複雑だったのはビジネス仕様だった ? / is-the-business-domain-the-real-complexity
hatsu38
0
460
ジョジョの世界をXRで再現する
mofurune
0
150
Unity6 URPによる海底をテーマにしたVJシステムの解説 | Unity Shader 完全に理解した 勉強会
gam0022
0
350
AI時代のコードレビューは人に向けるな、仕組みに向けろ
texmeijin
5
3.6k
TechTown - Creating Composable Callables in Contemporary C++
rollbear
0
100
ソニーのクラウド共通基盤の変遷とAI時代の開発スタイルに合わせた進化 / The Journey of Sony’s Common Cloud Platform and Its Evolution for AI-Native Development
kenjiyoneyama
0
250
Domain-Driven Transformation
hschwentner
2
2.3k
Simple Storage Service(S3) is not simple
iwatsukayura
0
260
Vue Fes Japan の “作る側”に関わってみて
naokihaba
0
150
個人開発者よ、Honoを使え(おじさんver)
tanahiro2010
2
240
golang-bob.pdf
iwatsukayura
0
130
When benchmarks go bad - what I learned from measuring performance wrong
hollycummins
0
200
Featured
See All Featured
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1.6k
Automating Front-end Workflow
addyosmani
1369
210k
Build The Right Thing And Hit Your Dates
maggiecrowley
39
3.5k
Collaborative Software Design: How to facilitate domain modelling decisions
baasie
1
340
The untapped power of vector embeddings
frankvandijk
2
1.9k
How STYLIGHT went responsive
nonsquared
100
6.3k
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
280
The Pragmatic Product Professional
lauravandoore
37
7.5k
職位にかかわらず全員がリーダーシップを発揮するチーム作り / Building a team where everyone can demonstrate leadership regardless of position
madoxten
69
67k
Fireside Chat
paigeccino
43
4.1k
VelocityConf: Rendering Performance Case Studies
addyosmani
331
25k
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 も怖かった