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
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
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
350
Rails deprecation warning に立ち向かう技術 / v.s. rails deprecation warnings
megane42
0
800
OSS コミットゴルフのすすめ / Let's play OSS-contribute-golf
megane42
0
130
ゆる計算理論ラジオ / P vs NP for beginner
megane42
1
280
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
共通化で考えるべきは、実装より公開する型だった
codeegg
0
220
광주소프트웨어마이스터고등학교 DevFest 특강 - 바이브 코딩 시대에서 주니어 개발자로 살아남는 방법
utilforever
1
110
AI駆動開発を妨げる技術的負債の解消アプローチ / ai-refactoring-approach
minodriven
17
8.9k
Hatena Engineer Seminar #37「言語モデルの活用に関する研究」
slashnephy
0
510
継続モナドとリアクティブプログラミング
yukikurage
3
520
信頼性について考えてみる(SRE NEXT 2026 miniLT)
hayama17
0
170
Creating Composable Callables in Contemporary C++
rollbear
0
200
吝嗇家のためのAI活用 / AI development for miser - ChatGPT + Issue Driven Development
tooppoo
0
180
Claude Team Plan導入・ガイド
tk3fftk
0
180
フィードバックで育てるAI開発
kotaminato
1
110
初めてのKubernetes 本番運用でハマった話
oku053
0
120
言語を使う側から、作る側へ。 自作 Lisp で得た新たな気づき。
andpad
0
110
Featured
See All Featured
A Guide to Academic Writing Using Generative AI - A Workshop
ks91
PRO
1
350
Noah Learner - AI + Me: how we built a GSC Bulk Export data pipeline
techseoconnect
PRO
0
220
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
2k
GraphQLの誤解/rethinking-graphql
sonatard
75
12k
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
760
Effective software design: The role of men in debugging patriarchy in IT @ Voxxed Days AMS
baasie
0
450
The Impact of AI in SEO - AI Overviews June 2024 Edition
aleyda
5
1.1k
Designing Experiences People Love
moore
143
24k
Practical Orchestrator
shlominoach
191
11k
Lessons Learnt from Crawling 1000+ Websites
charlesmeaden
PRO
1
1.4k
End of SEO as We Know It (SMX Advanced Version)
ipullrank
3
4.3k
What Being in a Rock Band Can Teach Us About Real World SEO
427marketing
0
1k
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 も怖かった