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
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
370
Rails deprecation warning に立ち向かう技術 / v.s. rails deprecation warnings
megane42
0
840
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
650
Other Decks in Programming
See All in Programming
動作中のプログラムの中身をリアルタイムに覗く / Realtime Debugger for CSharp with Roslyn
prota
1
820
速習iPhone Duo対応
yuukiw00w
1
700
選挙速報を多くのユーザーへ 届ける Live Activities 設計
hamayokokuririn
0
150
スマートフォンでモールス信号を送受信する 〜スマートフォンのLEDとカメラで作る光通信の設計と実装〜
atsuki_seo
0
160
標準パッケージに uuid が追加された 背景から見る Go らしい意思決定 / go_127_uuid_decision
convto
5
7.9k
TiDB Cloudのカスタムコントローラーによるオートスケール対応
takaidohigasi
0
130
仕様駆動開発による爆速プロダクト開発 / Bakusoku Spec Driven Development
kobakei
0
120
AI に Inclusive UI を書かせよう — Design Rules Skill で Compose UI を作り直す
theoriatec2024
1
510
アクセシビリティから考える情報設計
high_g_engineer
0
380
マイコン向けの軽量Ruby「PicoRuby」で各種デバイスを制御するネイティブアプリの実現手法
bash0c7
0
430
Starting & Sustaining Code-Based E2E Testing for Non-Coding QA Teams( #jasstniigata )
teyamagu
PRO
1
480
Webの地図
yosuke_furukawa
PRO
6
4.7k
Featured
See All Featured
Avoiding the “Bad Training, Faster” Trap in the Age of AI
tmiket
0
240
Winning Ecommerce Organic Search in an AI Era - #searchnstuff2025
aleyda
2
2.1k
Exploring the relationship between traditional SERPs and Gen AI search
raygrieselhuber
PRO
3
4.3k
Rebuilding a faster, lazier Slack
samanthasiow
85
9.6k
Leo the Paperboy
mayatellez
10
2.3k
What does AI have to do with Human Rights?
axbom
PRO
1
2.4k
A brief & incomplete history of UX Design for the World Wide Web: 1989–2019
jct
2
510
Kristin Tynski - Automating Marketing Tasks With AI
techseoconnect
PRO
0
520
From Legacy to Launchpad: Building Startup-Ready Communities
dugsong
0
330
Navigating the Design Leadership Dip - Product Design Week Design Leaders+ Conference 2024
apolaine
2
430
The Impact of AI in SEO - AI Overviews June 2024 Edition
aleyda
6
1.2k
Fireside Chat
paigeccino
43
4k
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 も怖かった