-
Notifications
You must be signed in to change notification settings - Fork 0
/
active_record_basics.html
536 lines (494 loc) · 31 KB
/
active_record_basics.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Active Record 基礎 — Ruby on Rails 指南</title>
<meta name="description" content="Ruby on Rails 指南:系統學習 Rails(Rails 4.2 版本)" >
<meta name="keywords" content="Ruby on Rails Guides 指南 中文 學習 免費 網路 Web 開發" >
<meta name="author" content="http://git.io/G_R1sA">
<meta property="fb:admins" content="1340181291">
<meta property="og:title" content="Active Record 基礎 — Ruby on Rails 指南" >
<meta property="og:site_name" content="Ruby on Rails 指南">
<meta property="og:image" content="http://rails.ruby.tw/images/rails_guides_cover.jpg">
<meta property="og:url" content="http://rails.ruby.tw/">
<meta property="og:type" content="article">
<meta property="og:description" content="Ruby on Rails 指南:系統學習 Rails(Rails 4.2 版本)">
<link rel="stylesheet" href="stylesheets/application.css">
<link href="http://fonts.googleapis.com/css?family=Noto+Sans:400,700|Noto+Serif:700|Source+Code+Pro" rel="stylesheet">
<link href="images/favicon.ico" rel="shortcut icon" type="image/x-icon">
</head>
<body class="guide">
<div id="fb-root"></div>
<script>(function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/zh-TW/sdk.js#xfbml=1&appId=837401439623727&version=v2.0";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));</script>
<script type="text/javascript">
window.twttr=(function(d,s,id){var t,js,fjs=d.getElementsByTagName(s)[0];if(d.getElementById(id)){return}js=d.createElement(s);js.id=id;js.src="https://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);return window.twttr||(t={_e:[],ready:function(f){t._e.push(f)}})}(document,"script","twitter-wjs"));
</script>
<div id="topNav">
<div class="wrapper">
<strong class="more-info-label">更多內容 <a href="http://rubyonrails.org/">rubyonrails.org:</a></strong>
<span class="red-button more-info-button">
更多內容
</span>
<ul class="more-info-links s-hidden">
<li class="more-info"><a href="http://rubyonrails.org/">綜覽</a></li>
<li class="more-info"><a href="http://rubyonrails.org/download">下載</a></li>
<li class="more-info"><a href="http://rubyonrails.org/deploy">部署</a></li>
<li class="more-info"><a href="https://github.com/rails/rails">原始碼</a></li>
<li class="more-info"><a href="http://rubyonrails.org/screencasts">影片</a></li>
<li class="more-info"><a href="http://rubyonrails.org/documentation">文件</a></li>
<li class="more-info"><a href="http://rubyonrails.org/community">社群</a></li>
<li class="more-info"><a href="http://weblog.rubyonrails.org/">Blog</a></li>
</ul>
</div>
</div>
<div id="header">
<div class="wrapper clearfix">
<h1><a href="index.html" title="回首頁">Guides.rubyonrails.org</a></h1>
<ul class="nav">
<li><a class="nav-item" href="index.html">首頁</a></li>
<li class="guides-index guides-index-large">
<a href="index.html" id="guidesMenu" class="guides-index-item nav-item">指南目錄</a>
<div id="guides" class="clearfix" style="display: none;">
<hr>
<dl class="L">
<dt>起步走</dt>
<dd><a href="getting_started.html">Rails 起步走</a></dd>
<dt>Models</dt>
<dd><a href="active_record_basics.html">Active Record 基礎</a></dd>
<dd><a href="active_record_migrations.html">Active Record 遷移</a></dd>
<dd><a href="active_record_validations.html">Active Record 驗證</a></dd>
<dd><a href="active_record_callbacks.html">Active Record 回呼</a></dd>
<dd><a href="association_basics.html">Active Record 關聯</a></dd>
<dd><a href="active_record_querying.html">Active Record 查詢</a></dd>
<dt>Views</dt>
<dd><a href="layouts_and_rendering.html">Rails 算繪與版型</a></dd>
<dd><a href="form_helpers.html">Action View 表單輔助方法</a></dd>
<dt>Controllers</dt>
<dd><a href="action_controller_overview.html">Action Controller 綜覽</a></dd>
<dd><a href="routing.html">Rails 路由:深入淺出</a></dd>
</dl>
<dl class="R">
<dt>深入了解</dt>
<dd><a href="active_support_core_extensions.html">Active Support 核心擴展</a></dd>
<dd><a href="i18n.html">Rails 國際化 API</a></dd>
<dd><a href="action_mailer_basics.html">Action Mailer 基礎</a></dd>
<dd><a href="active_job_basics.html">Active Job 基礎</a></dd>
<dd><a href="security.html">Rails 安全指南</a></dd>
<dd><a href="debugging_rails_applications.html">除錯 Rails 應用程式</a></dd>
<dd><a href="configuring.html">Rails 應用程式設定</a></dd>
<dd><a href="command_line.html">Rake 任務與 Rails 命令列工具</a></dd>
<dd><a href="asset_pipeline.html">Asset Pipeline</a></dd>
<dd><a href="working_with_javascript_in_rails.html">在 Rails 使用 JavaScript</a></dd>
<dd><a href="constant_autoloading_and_reloading.html">Constant Autoloading and Reloading</a></dd>
<dt>擴充 Rails</dt>
<dd><a href="rails_on_rack.html">Rails on Rack</a></dd>
<dd><a href="generators.html">客製與新建 Rails 產生器</a></dd>
<dd><a href="rails_application_templates.html">Rails 應用程式模版</a></dd>
<dt>貢獻 Ruby on Rails</dt>
<dd><a href="contributing_to_ruby_on_rails.html">貢獻 Ruby on Rails</a></dd>
<dd><a href="api_documentation_guidelines.html">API 文件準則</a></dd>
<dd><a href="ruby_on_rails_guides_guidelines.html">Ruby on Rails 指南準則</a></dd>
<dt>維護方針</dt>
<dd><a href="maintenance_policy.html">維護方針</a></dd>
<dt>發佈記</dt>
<dd><a href="upgrading_ruby_on_rails.html">升級 Ruby on Rails</a></dd>
<dd><a href="4_2_release_notes.html">Ruby on Rails 4.2 發佈記</a></dd>
<dd><a href="4_1_release_notes.html">Ruby on Rails 4.1 發佈記</a></dd>
<dd><a href="4_0_release_notes.html">Ruby on Rails 4.0 發佈記</a></dd>
<dd><a href="3_2_release_notes.html">Ruby on Rails 3.2 發佈記</a></dd>
<dd><a href="3_1_release_notes.html">Ruby on Rails 3.1 發佈記</a></dd>
<dd><a href="3_0_release_notes.html">Ruby on Rails 3.0 發佈記</a></dd>
<dd><a href="2_3_release_notes.html">Ruby on Rails 2.3 發佈記</a></dd>
<dd><a href="2_2_release_notes.html">Ruby on Rails 2.2 發佈記</a></dd>
<dt>Rails 指南翻譯術語</dt>
<dd><a href="translation_terms.html">翻譯術語</a></dd>
</dl>
</div>
</li>
<li><a class="nav-item" href="//github.com/docrails-tw/guides">貢獻翻譯</a></li>
<li><a class="nav-item" href="contributing_to_ruby_on_rails.html">貢獻</a></li>
<li><a class="nav-item" href="credits.html">致謝</a></li>
<li class="guides-index guides-index-small">
<select class="guides-index-item nav-item">
<option value="index.html">指南目錄</option>
<optgroup label="起步走">
<option value="getting_started.html">Rails 起步走</option>
</optgroup>
<optgroup label="Models">
<option value="active_record_basics.html">Active Record 基礎</option>
<option value="active_record_migrations.html">Active Record 遷移</option>
<option value="active_record_validations.html">Active Record 驗證</option>
<option value="active_record_callbacks.html">Active Record 回呼</option>
<option value="association_basics.html">Active Record 關聯</option>
<option value="active_record_querying.html">Active Record 查詢</option>
</optgroup>
<optgroup label="Views">
<option value="layouts_and_rendering.html">Rails 算繪與版型</option>
<option value="form_helpers.html">Action View 表單輔助方法</option>
</optgroup>
<optgroup label="Controllers">
<option value="action_controller_overview.html">Action Controller 綜覽</option>
<option value="routing.html">Rails 路由:深入淺出</option>
</optgroup>
<optgroup label="深入了解">
<option value="active_support_core_extensions.html">Active Support 核心擴展</option>
<option value="i18n.html">Rails 國際化 API</option>
<option value="action_mailer_basics.html">Action Mailer 基礎</option>
<option value="active_job_basics.html">Active Job 基礎</option>
<option value="security.html">Rails 安全指南</option>
<option value="debugging_rails_applications.html">除錯 Rails 應用程式</option>
<option value="configuring.html">Rails 應用程式設定</option>
<option value="command_line.html">Rake 任務與 Rails 命令列工具</option>
<option value="asset_pipeline.html">Asset Pipeline</option>
<option value="working_with_javascript_in_rails.html">在 Rails 使用 JavaScript</option>
<option value="constant_autoloading_and_reloading.html">Constant Autoloading and Reloading</option>
</optgroup>
<optgroup label="擴充 Rails">
<option value="rails_on_rack.html">Rails on Rack</option>
<option value="generators.html">客製與新建 Rails 產生器</option>
<option value="rails_application_templates.html">Rails 應用程式模版</option>
</optgroup>
<optgroup label="貢獻 Ruby on Rails">
<option value="contributing_to_ruby_on_rails.html">貢獻 Ruby on Rails</option>
<option value="api_documentation_guidelines.html">API 文件準則</option>
<option value="ruby_on_rails_guides_guidelines.html">Ruby on Rails 指南準則</option>
</optgroup>
<optgroup label="維護方針">
<option value="maintenance_policy.html">維護方針</option>
</optgroup>
<optgroup label="發佈記">
<option value="upgrading_ruby_on_rails.html">升級 Ruby on Rails</option>
<option value="4_2_release_notes.html">Ruby on Rails 4.2 發佈記</option>
<option value="4_1_release_notes.html">Ruby on Rails 4.1 發佈記</option>
<option value="4_0_release_notes.html">Ruby on Rails 4.0 發佈記</option>
<option value="3_2_release_notes.html">Ruby on Rails 3.2 發佈記</option>
<option value="3_1_release_notes.html">Ruby on Rails 3.1 發佈記</option>
<option value="3_0_release_notes.html">Ruby on Rails 3.0 發佈記</option>
<option value="2_3_release_notes.html">Ruby on Rails 2.3 發佈記</option>
<option value="2_2_release_notes.html">Ruby on Rails 2.2 發佈記</option>
</optgroup>
<optgroup label="Rails 指南翻譯術語">
<option value="translation_terms.html">翻譯術語</option>
</optgroup>
</select>
</li>
</ul>
</div>
</div>
</div>
<hr class="hide">
<div id="feature">
<div class="wrapper">
<h2>Active Record 基礎</h2><p>本篇介紹 Active Record。</p><p>讀完本篇,您將了解:</p>
<ul>
<li>物件關係映射(Object Relational Mapping)與 Active Record 是什麼,以及如何在 Rails 使用它們。</li>
<li>Active Record 如何融入 MVC 範式。</li>
<li>如何使用 Active Record Model 來處理存在關聯式資料庫的資料。</li>
<li>Active Record 資料庫綱要的命名慣例。</li>
<li>資料庫遷移、驗證與回呼的概念。</li>
</ul>
<div id="subCol">
<h3 class="chapter"><img src="images/chapters_icon.gif" alt="" />Chapters</h3>
<ol class="chapters">
<li>
<a href="#active-record-%E6%98%AF%E4%BB%80%E9%BA%BC%EF%BC%9F">Active Record 是什麼?</a>
<ul>
<li><a href="#active-record-%E6%A8%A1%E5%BC%8F">Active Record 模式</a></li>
<li><a href="#%E7%89%A9%E4%BB%B6%E9%97%9C%E8%81%AF%E6%98%A0%E5%B0%84">物件關聯映射</a></li>
<li><a href="#active-record-%E4%BD%9C%E7%82%BA-orm-%E6%A1%86%E6%9E%B6">Active Record 作為 ORM 框架</a></li>
</ul>
</li>
<li>
<a href="#active-record-%E4%B8%AD%E7%9A%84%E6%85%A3%E4%BE%8B%E5%8B%9D%E6%96%BC%E8%A8%AD%E5%AE%9A">Active Record 中的慣例勝於設定</a>
<ul>
<li><a href="#%E5%91%BD%E5%90%8D%E6%85%A3%E4%BE%8B">命名慣例</a></li>
<li><a href="#%E8%B3%87%E6%96%99%E5%BA%AB%E7%B6%B1%E8%A6%81%E6%85%A3%E4%BE%8B">資料庫綱要慣例</a></li>
</ul>
</li>
<li><a href="#%E6%96%B0%E5%A2%9E-active-record-models">新增 Active Record Models</a></li>
<li><a href="#%E8%A6%86%E5%AF%AB%E5%91%BD%E5%90%8D%E6%85%A3%E4%BE%8B">覆寫命名慣例</a></li>
<li>
<a href="#crud%EF%BC%9A%E8%AE%80%E5%AF%AB%E8%B3%87%E6%96%99">CRUD:讀寫資料</a>
<ul>
<li><a href="#%E6%96%B0%E5%A2%9E-create">新增 Create</a></li>
<li><a href="#%E8%AE%80%E5%8F%96-read">讀取 Read</a></li>
<li><a href="#%E6%9B%B4%E6%96%B0-update">更新 Update</a></li>
<li><a href="#%E5%88%AA%E9%99%A4-delete">刪除 Delete</a></li>
</ul>
</li>
<li><a href="#%E9%A9%97%E8%AD%89">驗證</a></li>
<li><a href="#%E5%9B%9E%E5%91%BC%EF%BC%88callbacks%EF%BC%89">回呼(Callbacks)</a></li>
<li><a href="#%E9%81%B7%E7%A7%BB">遷移</a></li>
</ol>
</div>
</div>
</div>
<div id="container">
<div class="wrapper">
<div id="mainCol">
<h3 id="active-record-是什麼?">1 Active Record 是什麼?</h3><p>Active Record 是 <a href="getting_started.html#the-mvc-architecture">MVC</a> 的 M(Model),表現商業邏輯與資料的層級。Active Record 負責新增與操作需要持久存在資料庫裡的資料。Active Record 本身是物件關聯映射(Object Relational Mapping)系統的描述,以 Active Record 模式實作。</p><h4 id="active-record-模式">1.1 Active Record 模式</h4><p>Active Record 模式出自 Martin Fowler 在其書:《Patterns of Enterprise Application Architecture》中<a href="http://www.martinfowler.com/eaaCatalog/activeRecord.html">所描述的 Active Record</a>。在 Active Record 模式裡,物件擁有持久化的資料與行為,Active Record 確保存取資料的邏輯是物件的一部分,進而教導使用者如何將物件寫入於讀出資料庫。</p><h4 id="物件關聯映射">1.2 物件關聯映射</h4><p>物件關聯映射,通常縮寫為 ORM。是一種技巧,將應用程式中複雜的物件,對應到關聯式資料庫管理系統中的資料表。使用 ORM,可以輕鬆儲存物件的特性與關係,取出來的時候也不需要撰寫 SQL 語句,總體上減少了與資料庫存取有關的程式碼。</p><h4 id="active-record-作為-orm-框架">1.3 Active Record 作為 ORM 框架</h4><p>Active Record 賦予我們許多功能,最重要幾個是:</p>
<ul>
<li>表示 Model 與資料。</li>
<li>表示 Model 之間的關係。</li>
<li>表示相關 Model 之間的繼承關係。</li>
<li>持久化資料存入資料庫的驗證。</li>
<li>以物件導向的風格操作資料庫。</li>
</ul>
<h3 id="active-record-中的慣例勝於設定">2 Active Record 中的慣例勝於設定</h3><p>使用其它程式語言撰寫應用程式時,可能會需要寫許多與設定有關的程式碼。大多數的 ORM 框架都是這樣。然而如果依循 Rails 的慣例,新建 Active Record Model 便只需要非常少的設定(某些情況甚至無需設定)。背後的概念是,如果多數時候大家都這麼設定應用程式,那這應該是預設的設定方式。因此,再無法遵循標準慣例的情況下,才需要額外設定。</p><h4 id="命名慣例">2.1 命名慣例</h4><p>Active Record 預設使用某種命名慣例來找出 Model 與資料表的對應關係。Rails 會將類別名稱轉成複數來找到對應的資料表。所以 <code>Book</code> 類對應的資料表便叫做 <code>books</code>。Rails 單複數轉換機制非常強大,能從單數轉複數、複數轉單數,單字的單複數形的不規則轉換,都能正確處理。類別名稱由兩個以上的單字組成時,Model 名稱應要遵循 Ruby 的命名慣例,採用駝峰式命名,而資料表名稱必須採用底線分隔。例子:</p>
<ul>
<li>資料表 - 複數形,由底線分隔多個單字。</li>
<li>
<p>Model 類別 - 單數形,第一個字母大寫。</p>
<table>
<thead>
<tr>
<th>Model / Class</th>
<th>Table / Schema</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>Article</code></td>
<td><code>articles</code></td>
</tr>
<tr>
<td><code>LineItem</code></td>
<td><code>line_items</code></td>
</tr>
<tr>
<td><code>Deer</code></td>
<td><code>deers</code></td>
</tr>
<tr>
<td><code>Mouse</code></td>
<td><code>mice</code></td>
</tr>
<tr>
<td><code>Person</code></td>
<td><code>people</code></td>
</tr>
</tbody>
</table>
</li>
</ul>
<h4 id="資料庫綱要慣例">2.2 資料庫綱要慣例</h4><p>Active Record 資料表欄位的命名慣例,取決於欄位的用途</p>
<ul>
<li><p><strong>外鍵</strong> - 應用資料表的單數形加上 <code>_id</code> 來命名,比如 <code>item_id</code>, <code>order_id</code>。Active Record 會在你建立 Model 之間的關聯時,尋找這種形式的欄位 <code>singularized_table_name_id</code>。</p></li>
<li><p><strong>主鍵</strong> - Active Record 預設會使用一個叫做 <code>id</code> 的整數欄位,作為資料表的主鍵。採用 <a href="migrations.html">Active Record
遷移</a> 來建立資料表時,這個欄位會自動產生。</p></li>
</ul>
<p>以下是某些選擇性的欄位名稱,會加入更多功能到 Active Record 實體:</p>
<ul>
<li>
<code>created_at</code> - 記錄首次建立時自動設定此欄位為當下的日期與時間。</li>
<li>
<code>updated_at</code> - 無論何時更新記錄時,會自動設定此欄位為當下的日期與時間。</li>
<li>
<code>lock_version</code> - 加入 <a href="http://api.rubyonrails.org/classes/ActiveRecord/Locking.html">optimistic
locking</a> 功能至 Model。</li>
<li>
<code>type</code> - 表示 Model 開啟了<a href="http://api.rubyonrails.org/classes/ActiveRecord/Base.html#class-ActiveRecord::Base-label-Single+table+inheritance">單表繼承</a>功能。</li>
<li>
<code>(association_name)_type</code> - 儲存
<a href="association_basics.html#polymorphic-associations">多態關聯</a> 所需的類型資料。</li>
<li>
<code>(table_name)_count</code> - 用來快取關聯物件的數量。舉例來說,<code>Article</code> Model 的 <code>comments_count</code> 便會為每篇文章快取評論的數量。</li>
</ul>
<div class="note"><p>雖然這些欄位名稱是選擇性的,但實際上是 Active Record 的保留字。如果要使用這些額外的功能,不要將這些保留字作為他用。比如,<code>type</code> 是用來設計單表繼承的資料表。如果沒有使用 STI 功能,試試用個類似的名稱如,“context” 來描述您在建模的資料。</p></div><h3 id="新增-active-record-models">3 新增 Active Record Models</h3><p>新增 Active Record Model 非常簡單。只需要建立一個 <code>ActiveRecord::Base</code> 的子類別即可:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class Product < ActiveRecord::Base
end
</pre>
</div>
<p>便會新增一個 <code>Product</code> Model,對應到資料庫的 <code>products</code> 表。資料表當中的每一列,皆會對應到 Model 實體的屬性。假設 <code>products</code> 以下面的 SQL 語句新建而成:</p><div class="code_container">
<pre class="brush: sql; gutter: false; toolbar: false">
CREATE TABLE products (
id int(11) NOT NULL auto_increment,
name varchar(255),
PRIMARY KEY (id)
);
</pre>
</div>
<p>按照上述的資料表綱要,可以寫出如下程式碼:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
p = Product.new
p.name = "Some Book"
puts p.name # "Some Book"
</pre>
</div>
<h3 id="覆寫命名慣例">4 覆寫命名慣例</h3><p>那要是需要不同於 Active Record 所提供的命名慣例怎麼辦?或者是 Rails 應用程式使用的資料來自老舊的資料庫?沒問題,覆寫預設的慣例非常簡單。</p><p>可以使用 <code>ActiveRecord::Base.table_name=</code> 方法來指定對應的資料表名稱:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class Product < ActiveRecord::Base
self.table_name = "PRODUCT"
end
</pre>
</div>
<p>如果修改了資料表的名稱,在測試裡會需要使用 <code>set_fixture_class</code> 來手動定義 fixture 的類別名稱。</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class FunnyJoke < ActiveSupport::TestCase
set_fixture_class funny_jokes: Joke
fixtures :funny_jokes
...
end
</pre>
</div>
<p>覆寫資料表中的欄位也是有可能的,比如使用 <code>ActiveRecord::Base.primary_key=</code> 方法將修改主鍵的名稱</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class Product < ActiveRecord::Base
self.primary_key = "product_id"
end
</pre>
</div>
<h3 id="crud:讀寫資料">5 CRUD:讀寫資料</h3><p>CRUD 是四種資料操作的簡稱:<strong>C</strong>reate,
<strong>R</strong>ead, <strong>U</strong>pdate and <strong>D</strong>elete,分別是新增、讀取、更新與刪除。Active Record 自動為應用程式新增處理資料表所需要的方法。</p><h4 id="新增-create">5.1 新增 Create</h4><p>Active Record 物件可以從 Hash、區塊(blcok)中建立出來,或者是建立後再設定也可以。<code>new</code> 方法回傳一個新的物件,而 <code>create</code> 會會傳新物件並存入資料庫。</p><p>舉個例子,<code>User</code> Model 有 <code>name</code> 與 <code>occupation</code> 屬性,以下是用 <code>create</code> 方法在資料庫新增一筆記錄的例子:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
user = User.create(name: "David", occupation: "Code Artist")
</pre>
</div>
<p>使用 <code>new</code> 方法,物件會實體化出來,但不會儲存:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
user = User.new
user.name = "David"
user.occupation = "Code Artist"
</pre>
</div>
<p>呼叫 <code>user.save</code> 會將該筆記錄存入資料庫。</p><p>最後,使用區塊的例子,會將 User.new 實體化出來的物件放入區塊裡,對個別屬性作設定:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
user = User.new do |u|
u.name = "David"
u.occupation = "Code Artist"
end
</pre>
</div>
<h4 id="讀取-read">5.2 讀取 Read</h4><p>Active Record 提供了豐富的 API 來存取資料庫裡的資料。下面是 Active Record 所提供的幾個資料存取方法用例:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
# return a collection with all users
users = User.all
</pre>
</div>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
# return the first user
user = User.first
</pre>
</div>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
# return the first user named David
david = User.find_by(name: 'David')
</pre>
</div>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
# find all users named David who are Code Artists and sort by created_at in reverse chronological order
users = User.where(name: 'David', occupation: 'Code Artist').order('created_at DESC')
</pre>
</div>
<p>關於對 Active Record Model 做查詢的內容,請參考 <a href="active_record_querying.html">Active Record
Query Interface</a>。</p><h4 id="更新-update">5.3 更新 Update</h4><p>一旦 Active Record 物件被取出來了,就可以對屬性修改,再存回資料庫。</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
user = User.find_by(name: 'David')
user.name = 'Dave'
user.save
</pre>
</div>
<p>修改屬性再儲存有簡寫方式,使用 Hash 來對應要修改的屬性,如下所示:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
user = User.find_by(name: 'David')
user.update(name: 'Dave')
</pre>
</div>
<p>一次更新多個屬性時用這招最有效。若是要批量更新多筆記錄,可以使用類別方法:<code>update_all</code>:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
User.update_all "max_login_attempts = 3, must_change_password = 'true'"
</pre>
</div>
<h4 id="刪除-delete">5.4 刪除 Delete</h4><p>既然可以取出 Active Record 物件做更新,同樣也可以將其從資料庫移除。</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
user = User.find_by(name: 'David')
user.destroy
</pre>
</div>
<h3 id="驗證">6 驗證</h3><p>Active Record 允許您在資料被存入資料庫之前,驗證資料的狀態。驗證有許多方法,比如可以檢查屬性的值是不是空的、是不是唯一的、資料庫裡是不是已經有一份?每種檢查方法有特定的書寫格式。</p><p>驗證是在把持久化資料存入資料庫前,需要審慎思量的問題。跟資料存入資料庫有關的二種方法 <code>save</code> 以及 <code>update</code>,在呼叫時會進行驗證。當這三個方法回傳值為 <code>false</code> 時,驗證失敗,將不會對資料庫進行任何操作。上述三個方法皆有對應的 BANG 方法:<code>save!</code> 以及 <code>update!</code>,這比原本的方法更嚴格些,一旦失敗會直接拋出 <code>ActiveRecord::RecordInvalid</code> 的異常。用個簡單例子來說明:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class User < ActiveRecord::Base
validates :name, presence: true
end
user = User.new
user.save # => false
user.save! # => ActiveRecord::RecordInvalid: Validation failed: Name can't be blank
</pre>
</div>
<p>了解更多關於驗證的內容,請參考:<a href="active_record_validations.html">Active Record Validations
guide</a>。</p><h3 id="回呼(callbacks)">7 回呼(Callbacks)</h3><p>Active Record 回呼允許您在 Model 生命週期裡對特定事件附加程式碼。這使您可以在特定事件發生時,執行特定的程式碼。比如向資料庫新增、更新、刪除某筆記錄等。了解更多關於回呼的內容,請參考:<a href="active_record_callbacks.html">Active Record Callbacks</a></p><h3 id="遷移">8 遷移</h3><p>Rails 提供了用來處理資料庫綱要的 DSL,稱為“遷移”。遷移存在檔案裡,可以對 Active Record 支持的任何資料庫,透過 <code>rake</code> 執行。以下是如何新建一張資料表:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class CreatePublications < ActiveRecord::Migration
def change
create_table :publications do |t|
t.string :title
t.text :description
t.references :publication_type
t.integer :publisher_id
t.string :publisher_type
t.boolean :single_issue
t.timestamps null: false
end
add_index :publications, :publication_type_id
end
end
</pre>
</div>
<p>Rails 持續追蹤提交到資料庫的檔案,並提供回滾功能。要真正的建立一張資料表,需要執行:<code>rake db:migrate</code>;要回滾則是執行:<code>rake db:rollback</code>。</p><p>注意以上的程式碼適用於任何資料庫,不管是 Oracle、PostgreSQL、MySQL 都可以。了解更多關於遷移的內容,請參考 <a href="migrations.html">Active Record Migrations</a>。</p>
<h3>反饋</h3>
<p>
歡迎幫忙改善指南的品質。
</p>
<p>
如發現任何錯誤之處,歡迎修正。開始貢獻前,可以先閱讀<a href="http://edgeguides.rubyonrails.org/contributing_to_ruby_on_rails.html#contributing-to-the-rails-documentation">貢獻指南:文件</a>。
</p>
<p>翻譯如有錯誤,深感抱歉,歡迎 <a href="https://github.com/docrails-tw/guides/fork">Fork</a> 修正,或至此處<a href="https://github.com/docsrails-tw/guides/issues/new">回報</a>。</p>
<p>
文章可能有未完成或過時的內容。請先檢查 <a href="http://edgeguides.rubyonrails.org">Edge Guides</a> 來確定問題在 master 是否已經修掉了。再上 master 補上缺少的文件。內容參考 <a href="ruby_on_rails_guides_guidelines.html">Ruby on Rails 指南準則</a>來了解行文風格。
</p>
<p>最後,任何關於 Ruby on Rails 文件的討論,歡迎至 <a href="http://groups.google.com/group/rubyonrails-docs">rubyonrails-docs 郵件論壇</a>。
</p>
</div>
</div>
</div>
<hr class="hide">
<div id="footer">
<div class="wrapper">
<p>本著作係採用<a href="https://creativecommons.org/licenses/by-sa/4.0/deed.zh_TW">創用 CC 姓名標示-相同方式分享 4.0 國際授權條款</a>授權。</p>
<p>“Rails”、“Ruby on Rails”,以及 Rails logo 為 David Heinemeier Hansson 的商標。版權所有。</p>
</div>
</div>
<script src="javascripts/jquery.min.js"></script>
<script src="javascripts/responsive-tables.js"></script>
<script src="javascripts/guides.js"></script>
<script src="javascripts/syntaxhighlighter/shCore.js"></script>
<script src="javascripts/syntaxhighlighter/shBrushRuby.js"></script>
<script src="javascripts/syntaxhighlighter/shBrushXml.js"></script>
<script src="javascripts/syntaxhighlighter/shBrushSql.js"></script>
<script src="javascripts/syntaxhighlighter/shBrushPlain.js"></script>
<script type="text/javascript">
SyntaxHighlighter.all();
$(guidesIndex.bind);
</script>
<script>
(function(i,s,o,g,r,a,m){i["GoogleAnalyticsObject"]=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,"script","//www.google-analytics.com/analytics.js","ga");
ga("create", "UA-49903900-1", "auto");
ga("require", "displayfeatures");
ga("send", "pageview");
</script>
</body>
</html>