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
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
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
790
OSS コミットゴルフのすすめ / Let's play OSS-contribute-golf
megane42
0
130
ゆる計算理論ラジオ / P vs NP for beginner
megane42
1
270
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
630
Other Decks in Programming
See All in Programming
Spring Security 実践 ─ GraphQL APIで実務に役立つ 認証・認可 を学ぶ
wagyu
0
250
1B+ /day規模のログを管理する技術
broadleaf
0
100
Inside Stream API
skrb
1
740
TSKaigi Night Talks 2026_TypeScriptでサプライチェーンの整合性を型に閉じ込める
geekplus_tech
0
400
Vue × Nuxt × Oxc どこまで使える?実運用の現在地
andpad
0
270
正しくソフトウェアを作る、前提を疑うための認知の視点 / doubt-premise
minodriven
21
6.8k
Performance Engineering for Everyone
elenatanasoiu
0
190
OSもどきOS
arkw
0
570
技術記事、 専門家としてのプログラマ、 言語化
mizchi
13
6.3k
エージェンティックRAGにAWSで入門しよう!
har1101
8
1.7k
AI 輔助遺留系統現代化的經驗分享
jame2408
1
810
気圧・高度・GPSを記録&可視化するアプリ「Koudo」を作った話
hjmkth
1
300
Featured
See All Featured
Redefining SEO in the New Era of Traffic Generation
szymonslowik
1
340
Docker and Python
trallard
47
3.9k
Neural Spatial Audio Processing for Sound Field Analysis and Control
skoyamalab
0
340
How to build a perfect <img>
jonoalderson
1
5.7k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
34
2.8k
Ecommerce SEO: The Keys for Success Now & Beyond - #SERPConf2024
aleyda
1
2k
Winning Ecommerce Organic Search in an AI Era - #searchnstuff2025
aleyda
1
2k
Primal Persuasion: How to Engage the Brain for Learning That Lasts
tmiket
0
370
Ethics towards AI in product and experience design
skipperchong
2
310
Agile that works and the tools we love
rasmusluckow
331
21k
How Fast Is Fast Enough? [PerfNow 2025]
tammyeverts
3
610
What's in a price? How to price your products and services
michaelherold
247
13k
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 も怖かった