-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathactive_record_callbacks.html
692 lines (632 loc) · 41.6 KB
/
active_record_callbacks.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
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>액티브 레코드 콜백 — Ruby on Rails Guides</title>
<link rel="stylesheet" type="text/css" href="stylesheets/style.css" data-turbolinks-track="reload">
<link rel="stylesheet" type="text/css" href="stylesheets/print.css" media="print">
<link rel="stylesheet" type="text/css" href="stylesheets/syntaxhighlighter/shCore.css" data-turbolinks-track="reload">
<link rel="stylesheet" type="text/css" href="stylesheets/syntaxhighlighter/shThemeRailsGuides.css" data-turbolinks-track="reload">
<link rel="stylesheet" type="text/css" href="stylesheets/fixes.css" data-turbolinks-track="reload">
<link href="images/favicon.ico" rel="shortcut icon" type="image/x-icon" />
<script src="javascripts/syntaxhighlighter.js" data-turbolinks-track="reload"></script>
<script src="javascripts/turbolinks.js" data-turbolinks-track="reload"></script>
<script src="javascripts/guides.js" data-turbolinks-track="reload"></script>
<script src="javascripts/responsive-tables.js" data-turbolinks-track="reload"></script>
<meta property="og:title" content="액티브 레코드 콜백 — Ruby on Rails Guides" />
<meta name="description" content="액티브 레코드 콜백본 가이드는 액티브 레코드 객체의 생명주기에 후크(hook, https://ko.wikipedia.org/wiki/후킹) 을 거는 방법을 알려 준다.본 가이드를 읽은 후 아래와 같은 내용을 알게 될 것이다. 액티브 레코드 객체의 생명주기. 객체 생명주기의 이벤트에 응답하는 콜백 메소드를 만드는 방법. 콜백의 일반적인 동작을 캡슐화하는 별도의 클래스를 만드는 방법." />
<meta property="og:description" content="액티브 레코드 콜백본 가이드는 액티브 레코드 객체의 생명주기에 후크(hook, https://ko.wikipedia.org/wiki/후킹) 을 거는 방법을 알려 준다.본 가이드를 읽은 후 아래와 같은 내용을 알게 될 것이다. 액티브 레코드 객체의 생명주기. 객체 생명주기의 이벤트에 응답하는 콜백 메소드를 만드는 방법. 콜백의 일반적인 동작을 캡슐화하는 별도의 클래스를 만드는 방법." />
<meta property="og:locale" content="en_US" />
<meta property="og:site_name" content="Ruby on Rails Guides" />
<meta property="og:image" content="https://avatars.githubusercontent.com/u/4223" />
<meta property="og:type" content="website" />
</head>
<body class="guide">
<div id="topNav">
<div class="wrapper">
<strong class="more-info-label">공식 웹사이트 <a href="https://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="https://weblog.rubyonrails.org/">블로그</a></li>
<li class="more-info"><a href="https://guides.rubyonrails.org/">영문가이드</a></li>
<li class="more-info"><a href="https://api.rubyonrails.org/">레일스API</a></li>
<li class="more-info"><a href="https://stackoverflow.com/questions/tagged/ruby-on-rails">질문하기</a></li>
<li class="more-info"><a href="https://github.com/rails/rails">GitHub에서 기여하기</a></li>
</ul>
</div>
</div>
<div id="header">
<div class="wrapper clearfix">
<h1><a href="index.html" title="Return to home page">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 />
<div class="guides-section-container">
<div class="guides-section">
<dt>시작하면서</dt>
<dd><a href="getting_started.html">레일스로 시작하기</a></dd>
</div>
<div class="guides-section">
<dt>모델</dt>
<dd><a href="active_record_basics.html">액티브 레코드 기본</a></dd>
<dd><a href="active_record_migrations.html">액티브 레코드 마이그레이션</a></dd>
<dd><a href="active_record_validations.html">액티브 레코드 유효성 검증</a></dd>
<dd><a href="active_record_callbacks.html">액티브 레코드 콜백</a></dd>
<dd><a href="association_basics.html">Active Record Associations</a></dd>
<dd><a href="active_record_querying.html">Active Record Query Interface</a></dd>
</div>
<div class="guides-section">
<dt>Views</dt>
<dd><a href="layouts_and_rendering.html">Layouts and Rendering in Rails</a></dd>
<dd><a href="form_helpers.html">Action View Form Helpers</a></dd>
</div>
<div class="guides-section">
<dt>Controllers</dt>
<dd><a href="action_controller_overview.html">Action Controller Overview</a></dd>
<dd><a href="routing.html">Rails Routing from the Outside In</a></dd>
</div>
<div class="guides-section">
<dt>Other Components</dt>
<dd><a href="active_support_core_extensions.html">Active Support Core Extensions</a></dd>
<dd><a href="action_mailer_basics.html">Action Mailer Basics</a></dd>
<dd><a href="active_job_basics.html">Active Job Basics</a></dd>
<dd><a href="active_storage_overview.html">Active Storage Overview</a></dd>
<dd><a href="action_cable_overview.html">Action Cable Overview</a></dd>
</div>
<div class="guides-section">
<dt>Digging Deeper</dt>
<dd><a href="i18n.html">Rails Internationalization (I18n) API</a></dd>
<dd><a href="testing.html">Testing Rails Applications</a></dd>
<dd><a href="security.html">Securing Rails Applications</a></dd>
<dd><a href="debugging_rails_applications.html">Debugging Rails Applications</a></dd>
<dd><a href="configuring.html">Configuring Rails Applications</a></dd>
<dd><a href="command_line.html">The Rails Command Line</a></dd>
<dd><a href="asset_pipeline.html">The Asset Pipeline</a></dd>
<dd><a href="working_with_javascript_in_rails.html">Working with JavaScript in Rails</a></dd>
<dd><a href="autoloading_and_reloading_constants.html">Autoloading and Reloading Constants (Zeitwerk Mode)</a></dd>
<dd><a href="autoloading_and_reloading_constants_classic_mode.html">Autoloading and Reloading Constants (Classic Mode)</a></dd>
<dd><a href="caching_with_rails.html">Caching with Rails: An Overview</a></dd>
<dd><a href="api_app.html">Using Rails for API-only Applications</a></dd>
</div>
<div class="guides-section">
<dt>Extending Rails</dt>
<dd><a href="rails_on_rack.html">Rails on Rack</a></dd>
<dd><a href="generators.html">Creating and Customizing Rails Generators & Templates</a></dd>
</div>
<div class="guides-section">
<dt>Contributions</dt>
<dd><a href="contributing_to_ruby_on_rails.html">Contributing to Ruby on Rails</a></dd>
<dd><a href="api_documentation_guidelines.html">API Documentation Guidelines</a></dd>
<dd><a href="ruby_on_rails_guides_guidelines.html">Guides Guidelines</a></dd>
</div>
<div class="guides-section">
<dt>Policies</dt>
<dd><a href="maintenance_policy.html">Maintenance Policy</a></dd>
</div>
<div class="guides-section">
<dt>Release Notes</dt>
<dd><a href="upgrading_ruby_on_rails.html">Upgrading Ruby on Rails</a></dd>
<dd><a href="6_0_release_notes.html">Version 6.0 - August 2019</a></dd>
<dd><a href="5_2_release_notes.html">Version 5.2 - April 2018</a></dd>
<dd><a href="5_1_release_notes.html">Version 5.1 - April 2017</a></dd>
<dd><a href="5_0_release_notes.html">Version 5.0 - June 2016</a></dd>
<dd><a href="4_2_release_notes.html">Version 4.2 - December 2014</a></dd>
<dd><a href="4_1_release_notes.html">Version 4.1 - April 2014</a></dd>
<dd><a href="4_0_release_notes.html">Version 4.0 - June 2013</a></dd>
<dd><a href="3_2_release_notes.html">Version 3.2 - January 2012</a></dd>
<dd><a href="3_1_release_notes.html">Version 3.1 - August 2011</a></dd>
<dd><a href="3_0_release_notes.html">Version 3.0 - August 2010</a></dd>
<dd><a href="2_3_release_notes.html">Version 2.3 - March 2009</a></dd>
<dd><a href="2_2_release_notes.html">Version 2.2 - November 2008</a></dd>
</div>
</div>
</div>
</li>
<li><a class="nav-item" href="contributing_to_ruby_on_rails.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">레일스로 시작하기</option>
</optgroup>
<optgroup label="모델">
<option value="active_record_basics.html">액티브 레코드 기본</option>
<option value="active_record_migrations.html">액티브 레코드 마이그레이션</option>
<option value="active_record_validations.html">액티브 레코드 유효성 검증</option>
<option value="active_record_callbacks.html">액티브 레코드 콜백</option>
<option value="association_basics.html">Active Record Associations</option>
<option value="active_record_querying.html">Active Record Query Interface</option>
</optgroup>
<optgroup label="Views">
<option value="layouts_and_rendering.html">Layouts and Rendering in Rails</option>
<option value="form_helpers.html">Action View Form Helpers</option>
</optgroup>
<optgroup label="Controllers">
<option value="action_controller_overview.html">Action Controller Overview</option>
<option value="routing.html">Rails Routing from the Outside In</option>
</optgroup>
<optgroup label="Other Components">
<option value="active_support_core_extensions.html">Active Support Core Extensions</option>
<option value="action_mailer_basics.html">Action Mailer Basics</option>
<option value="active_job_basics.html">Active Job Basics</option>
<option value="active_storage_overview.html">Active Storage Overview</option>
<option value="action_cable_overview.html">Action Cable Overview</option>
</optgroup>
<optgroup label="Digging Deeper">
<option value="i18n.html">Rails Internationalization (I18n) API</option>
<option value="testing.html">Testing Rails Applications</option>
<option value="security.html">Securing Rails Applications</option>
<option value="debugging_rails_applications.html">Debugging Rails Applications</option>
<option value="configuring.html">Configuring Rails Applications</option>
<option value="command_line.html">The Rails Command Line</option>
<option value="asset_pipeline.html">The Asset Pipeline</option>
<option value="working_with_javascript_in_rails.html">Working with JavaScript in Rails</option>
<option value="autoloading_and_reloading_constants.html">Autoloading and Reloading Constants (Zeitwerk Mode)</option>
<option value="autoloading_and_reloading_constants_classic_mode.html">Autoloading and Reloading Constants (Classic Mode)</option>
<option value="caching_with_rails.html">Caching with Rails: An Overview</option>
<option value="api_app.html">Using Rails for API-only Applications</option>
</optgroup>
<optgroup label="Extending Rails">
<option value="rails_on_rack.html">Rails on Rack</option>
<option value="generators.html">Creating and Customizing Rails Generators & Templates</option>
</optgroup>
<optgroup label="Contributions">
<option value="contributing_to_ruby_on_rails.html">Contributing to Ruby on Rails</option>
<option value="api_documentation_guidelines.html">API Documentation Guidelines</option>
<option value="ruby_on_rails_guides_guidelines.html">Guides Guidelines</option>
</optgroup>
<optgroup label="Policies">
<option value="maintenance_policy.html">Maintenance Policy</option>
</optgroup>
<optgroup label="Release Notes">
<option value="upgrading_ruby_on_rails.html">Upgrading Ruby on Rails</option>
<option value="6_0_release_notes.html">Version 6.0 - August 2019</option>
<option value="5_2_release_notes.html">Version 5.2 - April 2018</option>
<option value="5_1_release_notes.html">Version 5.1 - April 2017</option>
<option value="5_0_release_notes.html">Version 5.0 - June 2016</option>
<option value="4_2_release_notes.html">Version 4.2 - December 2014</option>
<option value="4_1_release_notes.html">Version 4.1 - April 2014</option>
<option value="4_0_release_notes.html">Version 4.0 - June 2013</option>
<option value="3_2_release_notes.html">Version 3.2 - January 2012</option>
<option value="3_1_release_notes.html">Version 3.1 - August 2011</option>
<option value="3_0_release_notes.html">Version 3.0 - August 2010</option>
<option value="2_3_release_notes.html">Version 2.3 - March 2009</option>
<option value="2_2_release_notes.html">Version 2.2 - November 2008</option>
</optgroup>
</select>
</li>
</ul>
</div>
</div>
<hr class="hide" />
<div id="feature">
<div class="wrapper">
<h2 id="active-record-callbacks">액티브 레코드 콜백</h2><p>본 가이드는 액티브 레코드 객체의 생명주기에 후크(hook, <a href="https://ko.wikipedia.org/wiki/%ED%9B%84%ED%82%B9">https://ko.wikipedia.org/wiki/후킹</a>) 을 거는 방법을 알려 준다.</p><p>본 가이드를 읽은 후 아래와 같은 내용을 알게 될 것이다.</p>
<ul>
<li>액티브 레코드 객체의 생명주기.</li>
<li>객체 생명주기의 이벤트에 응답하는 콜백 메소드를 만드는 방법.</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="#the-object-life-cycle">액티브 레코드 객체의 생명주기</a></li>
<li>
<a href="#callbacks-overview">콜백 개요</a>
<ul>
<li><a href="#callback-registration">콜백 등록</a></li>
</ul>
</li>
<li>
<a href="#available-callbacks">가용한 콜백</a>
<ul>
<li><a href="#creating-an-object">액티브 레코드 객체 생성하기</a></li>
<li><a href="#updating-an-object">액티브 레코드 객체 업데이트하기</a></li>
<li><a href="#destroying-an-object">액티브 레코드 객체 삭제하기</a></li>
<li><a href="#after_initialize-and-after_find"><code>after_initialize</code> 와 <code>after_find</code></a></li>
<li><a href="#after-touch"><code>after_touch</code></a></li>
</ul>
</li>
<li><a href="#running-callbacks">콜백 실행하기</a></li>
<li><a href="#skipping-callbacks">콜백 건너뛰기</a></li>
<li><a href="#halting-execution">실행 중단</a></li>
<li><a href="#relational-callbacks">관계형 콜백</a></li>
<li>
<a href="#conditional-callbacks">조건부 콜백</a>
<ul>
<li><a href="#using-if-and-unless-with-a-symbol">심볼을 사용하여 조건을 지정할 때</a></li>
<li><a href="#using-if-and-unless-with-a-proc"><code>Proc</code>를 사용하여 조건을 지정할 때</a></li>
<li><a href="#multiple-conditions-for-callbacks">다중 조건부 콜백</a></li>
<li><a href="#combining-callback-conditions">콜백 조건 결합하기</a></li>
</ul>
</li>
<li><a href="#callback-classes">콜백 클래스</a></li>
<li><a href="#transaction-callbacks">트랜잭션 콜백</a></li>
</ol>
</div>
</div>
</div>
<div id="container">
<div class="wrapper">
<div id="mainCol">
<h3 id="the-object-life-cycle"><a class="anchorlink" href="#the-object-life-cycle">1 액티브 레코드 객체의 생명주기</a></h3><p>레일스 애플리케이션이 정상적으로 작동하는 동안 객체가 생성, 업데이트, 파괴될 수 있다. 액티브 레코드는 이 객체 생명주기에 대한 후크를 제공하므로써 애플리케이션과 데이터를 제어할 수 있다.</p><p>콜백을 사용하면 액티브 레코드 객체의 상태 변경 전후에 로직을 트리거할 수 있다.</p><h3 id="callbacks-overview"><a class="anchorlink" href="#callbacks-overview">2 콜백 개요</a></h3><p>콜백은 객체 생명주기의 특정 순간에 호출되는 메소드이다. 콜백을 사용하면 데이터베이스에서 액티브 레코드 객체를 생성, 저장, 업데이트, 삭제, 검증 또는 로드할 때마다 실행될 코드를 작성할 수 있다.</p><h4 id="callback-registration"><a class="anchorlink" href="#callback-registration">2.1 콜백 등록</a></h4><p>가용한 콜백을 사용하려면 콜백을 등록해야 한다. 콜백을 일반 메소드로 구현한 후 매크로 스타일 클래스 메소드를 사용하여 콜백으로 등록할 수 있다.</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class User < ApplicationRecord
validates :login, :email, presence: true
before_validation :ensure_login_has_a_value
private
def ensure_login_has_a_value
if login.nil?
self.login = email unless email.blank?
end
end
end
</pre>
</div>
<p>매크로 스타일 클래스 메소드는 블록을 받을 수도 있다. 블록 내부의 코드가 너무 짧아 한 줄에 들어가는 경우 이 스타일을 사용한다.</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class User < ApplicationRecord
validates :login, :email, presence: true
before_create do
self.name = login.capitalize if name.blank?
end
end
</pre>
</div>
<p>콜백은 특정 생명주기 이벤트에서만 발생하도록 등록할 수도 있다.</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class User < ApplicationRecord
before_validation :normalize_name, on: :create
# :on takes an array as well
after_validation :set_location, on: [ :create, :update ]
private
def normalize_name
self.name = name.downcase.titleize
end
def set_location
self.location = LocationService.query(self)
end
end
</pre>
</div>
<p>콜백 메소드를 private로 선언하는 것이 좋다. public 상태로 둘 경우 모델 외부에서 호출하여 객체 캡슐화 원칙을 위반할 수 있기 때문이다.</p><h3 id="available-callbacks"><a class="anchorlink" href="#available-callbacks">3 가용한 콜백</a></h3><p>다음은 사용 가능한 모든 액티브 레코드 콜백 목록이며 각 동작 중에 호출되는 순서와 동일한 순서로 나열되어 있다.</p><h4 id="creating-an-object"><a class="anchorlink" href="#creating-an-object">3.1 액티브 레코드 객체 생성하기</a></h4>
<ul>
<li><code>before_validation</code></li>
<li><code>after_validation</code></li>
<li><code>before_save</code></li>
<li><code>around_save</code></li>
<li><code>before_create</code></li>
<li><code>around_create</code></li>
<li><code>after_create</code></li>
<li><code>after_save</code></li>
<li><code>after_commit/after_rollback</code></li>
</ul>
<h4 id="updating-an-object"><a class="anchorlink" href="#updating-an-object">3.2 액티브 레코드 객체 업데이트하기</a></h4>
<ul>
<li><code>before_validation</code></li>
<li><code>after_validation</code></li>
<li><code>before_save</code></li>
<li><code>around_save</code></li>
<li><code>before_update</code></li>
<li><code>around_update</code></li>
<li><code>after_update</code></li>
<li><code>after_save</code></li>
<li><code>after_commit/after_rollback</code></li>
</ul>
<h4 id="destroying-an-object"><a class="anchorlink" href="#destroying-an-object">3.3 액티브 레코드 객체 삭제하기</a></h4>
<ul>
<li><code>before_destroy</code></li>
<li><code>around_destroy</code></li>
<li><code>after_destroy</code></li>
<li><code>after_commit/after_rollback</code></li>
</ul>
<div class="warning"><p><code>after_save</code>는 create와 update 모두에서 실행되지만 해당 매크로 호출이 실행된 순서에 관계없이 항상 구체적인 콜백 <code>after_create</code> 와 <code>after_update</code> <em>직후</em> 에 실행된다.</p></div><div class="note"><p><code>before_destroy</code> 콜백은 <code>dependent: :destroy</code> 관계 선언 전에 위치해야 하며(또는 <code>prepend: true</code> 옵션을 사용한다.), 레코드가 <code>dependent: :destroy</code>에 의해 삭제되기 전에 실행되도록 해야 한다.</p></div><h4 id="after_initialize-and-after_find"><a class="anchorlink" href="#after_initialize-and-after_find">3.4 <code>after_initialize</code> 와 <code>after_find</code></a></h4><p><code>after_initialize</code> 콜백은 <code>new</code>를 직접 사용하거나 데이터베이스에서 레코드를 로드할 때 액티브 레코드 객체가 인스턴스화될 때마다 호출된다. 액티브 레코드 <code>initialize</code> 메소드를 직접 오버라이드할 필요가 없기 때문에 유용 할 수 있다.</p><p><code>after_find</code> 콜백은 Active Record가 데이터베이스에서 레코드를 로드할 때마다 호출된다. 둘 다 정의 된 경우 <code>after_find</code>는 <code>after_initialize</code> 전에 호출된다.</p><p><code>after_initialize</code> 와 <code>after_find</code> 콜백에는 <code>before_*</code> 대응 콜백이 없지만 다른 액티브 레코드 콜백처럼 등록할 수 있다.</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class User < ApplicationRecord
after_initialize do |user|
puts "You have initialized an object!"
end
after_find do |user|
puts "You have found an object!"
end
end
>> User.new
You have initialized an object!
=> #<User id: nil>
>> User.first
You have found an object!
You have initialized an object!
=> #<User id: 1>
</pre>
</div>
<h4 id="after-touch"><a class="anchorlink" href="#after-touch">3.5 <code>after_touch</code></a></h4><p><code>after_touch</code> 콜백은 액티브 레코드 객체가 touch될 때마다 호출된다.</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class User < ApplicationRecord
after_touch do |user|
puts "You have touched an object"
end
end
>> u = User.create(name: 'Kuldeep')
=> #<User id: 1, name: "Kuldeep", created_at: "2013-11-25 12:17:49", updated_at: "2013-11-25 12:17:49">
>> u.touch
You have touched an object
=> true
</pre>
</div>
<p><code>belongs_to</code>와 함께 사용할 수 있다.</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class Employee < ApplicationRecord
belongs_to :company, touch: true
after_touch do
puts 'An Employee was touched'
end
end
class Company < ApplicationRecord
has_many :employees
after_touch :log_when_employees_or_company_touched
private
def log_when_employees_or_company_touched
puts 'Employee/Company was touched'
end
end
>> @employee = Employee.last
=> #<Employee id: 1, company_id: 1, created_at: "2013-11-25 17:04:22", updated_at: "2013-11-25 17:05:05">
# triggers @employee.company.touch
>> @employee.touch
An Employee was touched
Employee/Company was touched
=> true
</pre>
</div>
<h3 id="running-callbacks"><a class="anchorlink" href="#running-callbacks">4 콜백 실행하기</a></h3><p>아래의 메소드는 콜백을 트리거한다.</p>
<ul>
<li><code>create</code></li>
<li><code>create!</code></li>
<li><code>destroy</code></li>
<li><code>destroy!</code></li>
<li><code>destroy_all</code></li>
<li><code>save</code></li>
<li><code>save!</code></li>
<li><code>save(validate: false)</code></li>
<li><code>toggle!</code></li>
<li><code>touch</code></li>
<li><code>update_attribute</code></li>
<li><code>update</code></li>
<li><code>update!</code></li>
<li><code>valid?</code></li>
</ul>
<p>또한, 아래의 finder 메소드는 <code>after_find</code> 콜백을 트리거한다.</p>
<ul>
<li><code>all</code></li>
<li><code>first</code></li>
<li><code>find</code></li>
<li><code>find_by</code></li>
<li><code>find_by_*</code></li>
<li><code>find_by_*!</code></li>
<li><code>find_by_sql</code></li>
<li><code>last</code></li>
</ul>
<p>특정 클래스의 새로운 객체가 초기화될 때마다 <code>after_initialize</code> 콜백이 트리거된다. </p><div class="note"><p><code>find_by_*</code> 와 <code>find_by_*!</code> 메소드는 모든 속성에 대해서 자동으로 생성되는 동적 finder 들이다. <a href="active_record_querying.html#dynamic-finders">Dynamic finders section</a>에서 이에 관한 더 많은 것을 배울 수 있다.</p></div><h3 id="skipping-callbacks"><a class="anchorlink" href="#skipping-callbacks">5 콜백 건너뛰기</a></h3><p>유효성 검증과 같이, 아래의 메소드를 사용할 때도 콜백을 트리거하지 않을 수 있다. </p>
<ul>
<li><code>decrement!</code></li>
<li><code>decrement_counter</code></li>
<li><code>delete</code></li>
<li><code>delete_all</code></li>
<li><code>increment!</code></li>
<li><code>increment_counter</code></li>
<li><code>update_column</code></li>
<li><code>update_columns</code></li>
<li><code>update_all</code></li>
<li><code>update_counters</code></li>
</ul>
<p>그러나 중요한 비즈니스 규칙과 애플리케이션 논리가 콜백에 보관될 수 있으므로 이러한 메소드들은 주의해서 사용해야 한다. 잠재적인 영향을 이해하지 않고 이를 무시하면 유효하지 않은 데이터가 발생할 수 있다.</p><h3 id="halting-execution"><a class="anchorlink" href="#halting-execution">6 실행 중단</a></h3><p>모델에 콜백을 새로 등록하기 시작하면 실행 대기 상태가 된다. 이 대기열에는 모든 모델의 유효성 검사, 등록된 콜백 및 실행할 데이터베이스 작업이 포함된다.</p><p>전체 콜백 체인은 트랜잭션으로 래핑된다. 콜백에서 예외가 발생하면 실행 체인이 중지되고 ROLLBACK이 발생된다. 의도적으로 체인 사용을 중지하려면,</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
throw :abort
</pre>
</div>
<div class="warning"><p>콜백 체인이 정지된 후 <code>ActiveRecord::Rollback</code> 또는 <code>ActiveRecord::RecordInvalid</code> 가 아닌 예외는 레일스에 의해 다시 발생한다. <code>ActiveRecord::Rollback</code> 또는 <code>ActiveRecord::RecordInvalid</code> 이외의 예외가 발생하면 코드가 깨지게 되어(보통 <code>true</code> 또는 <code>false</code>를 반환하려고 시도하는) <code>save</code> 및 <code>update</code> 와 같은 메소드가 예외를 발생시키지 않게 된다.</p></div><h3 id="relational-callbacks"><a class="anchorlink" href="#relational-callbacks">7 관계형 콜백</a></h3><p>콜백은 모델 관계를 통해 작동하며 이를 정의할 수도 있다. 사용자에게 많은 기사(읽은거리)가 있는 예를 가정한다. 사용자가 삭제되면 사용자의 기사도 폐기해야 한다. <code>Article</code> 모델과의 관계를 통해 <code>after_destroy</code> 콜백을<code>User</code> 모델에 추가해 보면 아래와 같다. </p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class User < ApplicationRecord
has_many :articles, dependent: :destroy
end
class Article < ApplicationRecord
after_destroy :log_destroy_action
def log_destroy_action
puts 'Article destroyed'
end
end
>> user = User.first
=> #<User id: 1>
>> user.articles.create!
=> #<Article id: 1, user_id: 1>
>> user.destroy
Article destroyed
=> #<User id: 1>
</pre>
</div>
<h3 id="conditional-callbacks"><a class="anchorlink" href="#conditional-callbacks">8 조건부 콜백</a></h3><p>유효성 검증과 마찬가지로 주어진 predicate 메소드(true/false 를 반환하는 메소드)의 만족도에 따라 콜백 메소드 호출을 조건부로 작성할 수도 있다. <code>:if</code> 및 <code>:unless</code> 옵션을 사용하여 이 작업을 수행 할 수 있다. 이 옵션은 심볼, <code>Proc</code>, <code>Array</code> 형태로 지정하여 사용할 수 있다. 콜백이 호출<strong>되어야 하는</strong> 조건을 지정할 때 <code>:if</code> 옵션을 사용할 수 있다. 콜백이 호출되지 <strong>않아야 하는</strong> 조건을 지정하려면 <code>:unless</code> 옵션을 사용할 수 있다.</p><h4 id="using-if-and-unless-with-a-symbol"><a class="anchorlink" href="#using-if-and-unless-with-a-symbol">8.1 심볼을 사용하여 조건을 지정할 때</a></h4><p><code>:if</code> 및 <code>:unless</code> 옵션을 콜백 직전에 호출될 predicate 메소드의 이름에 해당하는 심볼과 연관시킬 수 있다. <code>:if</code> 옵션을 사용하는 경우, predicate 메소드가 false를 리턴하면 콜백이 실행되지 않는다. <code>:unless</code> 옵션을 사용할 때, predicate 메소드가 true를 리턴하면 콜백이 실행되지 않는다. 이것이 가장 일반적인 옵션이다. 이러한 등록 폼을 사용하면 콜백 실행 여부를 확인하기 위해 호출해야 하는 여러 가지 predicate 메소드를 등록 할 수도 있다.</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class Order < ApplicationRecord
before_save :normalize_card_number, if: :paid_with_card?
end
</pre>
</div>
<h4 id="using-if-and-unless-with-a-proc"><a class="anchorlink" href="#using-if-and-unless-with-a-proc">8.2 <code>Proc</code>를 사용하여 조건을 지정할 때</a></h4><p><code>:if</code> 와 <code>:unless</code>를 <code>Proc</code> 객체와 연관시킬 수 있다. 이 옵션은 짧은 유효성 검증 메소드(일반적으로 한줄 코딩에 적합한)을 작성할 때 가장 적합합니다.</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class Order < ApplicationRecord
before_save :normalize_card_number,
if: Proc.new { |order| order.paid_with_card? }
end
</pre>
</div>
<p>proc는 해당 객체의 특정 컨텍스에서 평가되므로 아래와 같이 작성할 수도 있다.</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class Order < ApplicationRecord
before_save :normalize_card_number, if: Proc.new { paid_with_card? }
end
</pre>
</div>
<h4 id="multiple-conditions-for-callbacks"><a class="anchorlink" href="#multiple-conditions-for-callbacks">8.3 다중 조건부 콜백</a></h4><p>조건부 콜백을 작성할 때 동일한 콜백 선언에서 <code>:if</code> 와 <code>:unless</code>를 함께 사용할 수 있다. </p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class Comment < ApplicationRecord
after_create :send_email_to_author, if: :author_wants_emails?,
unless: Proc.new { |comment| comment.article.ignore_comments? }
end
</pre>
</div>
<h4 id="combining-callback-conditions"><a class="anchorlink" href="#combining-callback-conditions">8.4 콜백 조건 결합하기</a></h4><p>여러 조건이 결합하여 콜백 발생 여부를 결정할 때 <code>Array</code>를 사용할 수 있다. 또한 동일한 콜백에 <code>:if</code> 와 <code>:unless</code>를 함께 적용할 수 있다.</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class Comment < ApplicationRecord
after_create :send_email_to_author,
if: [Proc.new { |c| c.user.allow_send_email? }, :author_wants_emails?],
unless: Proc.new { |c| c.article.ignore_comments? }
end
</pre>
</div>
<p>콜백은 모든 <code>:if</code> 조건이 <code>true</code>로 평가되고 <code>:unless</code> 조건 중 어느 것도 <code>true</code>로 평가되지 않는 경우에만 실행된다.</p><h3 id="callback-classes"><a class="anchorlink" href="#callback-classes">9 콜백 클래스</a></h3><p>때로는 작성하는 콜백 메소드가 다른 모델에서 재사용하기에도 충분할 정도로 유용할 때가 있다. 액티브 레코드를 사용하면 콜백 메소드를 캡슐화하는 클래스를 작성할 수 있으므로 재사용이 매우 쉬워진다.</p><p>아래의 예는 <code>PictureFile</code> 모델에 대한 <code>after_destroy</code> 콜백을 사용하여 클래스를 만드는 것이다.</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class PictureFileCallbacks
def after_destroy(picture_file)
if File.exist?(picture_file.filepath)
File.delete(picture_file.filepath)
end
end
end
</pre>
</div>
<p>위와 같이 클래스 내에서 선언되면 콜백 메서드는 모델 객체를 매개 변수로 받는다. 이제 모델에서 콜백 클래스를 사용할 수 있다.</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class PictureFile < ApplicationRecord
after_destroy PictureFileCallbacks.new
end
</pre>
</div>
<p>콜백을 인스턴스 메소드로 선언했기 때문에 <code>PictureFileCallbacks</code> 객체를 새로 인스턴스화해야 했었던 것에 주의한다. 이는 콜백이 인스턴스화된 객체의 상태를 사용하는 경우 특히 유용하다. 그러나 종종 콜백을 클래스 메소드로 선언하는 것이 더 합리적일 때가 있다. </p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class PictureFileCallbacks
def self.after_destroy(picture_file)
if File.exist?(picture_file.filepath)
File.delete(picture_file.filepath)
end
end
end
</pre>
</div>
<p>콜백 메소드가 이런 식으로 선언되면 <code>PictureFileCallbacks</code> 객체를 인스턴스화 할 필요가 없다.</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class PictureFile < ApplicationRecord
after_destroy PictureFileCallbacks
end
</pre>
</div>
<p>콜백 클래스 내에서 원하는 만큼의 콜백을 선언 할 수 있다.</p><h3 id="transaction-callbacks"><a class="anchorlink" href="#transaction-callbacks">10 트랜잭션 콜백</a></h3><p>데이터베이스 트랜잭션이 완료되면 트리거되는 <code>after_commit</code> 과<code>after_rollback</code> 의 두 가지 추가 콜백이 있다. 이 콜백은 데이터베이스 변경이 커밋되거나 롤백 될 때까지 실행되지 않는다는 점을 제외하면 <code>after_save</code> 콜백과 매우 유사하다. 액티브 레코드 모델이 데이터베이스 트랜잭션의 일부가 아닌 외부 시스템과 상호 작용해야 할 때 가장 유용하다.</p><p>예를 들어, 해당 레코드가 삭제된 후 <code>PictureFile</code> 모델이 파일을 삭제해야 하는 이전 예를 돌이켜 보자. <code>after_destroy</code> 콜백이 호출되고 트랜잭션이 롤백된 후 예외가 발생하면 파일이 삭제되고 모델이 일관성이 없는 상태로 남게 된다. 예를 들어, 아래 코드의 <code>picture_file_2</code>가 유효하지 않아 <code>save!</code> 메소드에서 에러가 발생한다고 가정하자.</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
PictureFile.transaction do
picture_file_1.destroy
picture_file_2.save!
end
</pre>
</div>
<p><code>after_commit</code> 콜백을 사용하여 이 경우를 설명 할 수 있다.</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class PictureFile < ApplicationRecord
after_commit :delete_picture_file_from_disk, on: :destroy
def delete_picture_file_from_disk
if File.exist?(filepath)
File.delete(filepath)
end
end
end
</pre>
</div>
<div class="note"><p><code>:on</code> 옵션은 콜백 발생 시점을 지정한다. <code>:on</code> 옵션을 지정하지 않으면 모든 동작에 대해 콜백이 발생한다.</p></div><p>create, update 또는 delete에서만 <code>after_commit</code> 콜백을 사용하는 것이 일반적이므로 해당 작업에 대한 별칭이 있다.</p>
<ul>
<li><code>after_create_commit</code></li>
<li><code>after_update_commit</code></li>
<li><code>after_destroy_commit</code></li>
</ul>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class PictureFile < ApplicationRecord
after_destroy_commit :delete_picture_file_from_disk
def delete_picture_file_from_disk
if File.exist?(filepath)
File.delete(filepath)
end
end
end
</pre>
</div>
<div class="warning"><p>트랜잭션이 완료되면 해당 트랜잭션 내에서 생성, 업데이트 또는 삭제된 모든 모델에 대해 <code>after_commit</code> 또는 <code>after_rollback</code> 콜백이 호출된다. 그러나 이러한 콜백 중 하나에서 예외가 발생하면 예외가 파급되어 나머지 <code>after_commit</code> 또는<code>after_rollback</code> 메소드는 실행되지 <em>않게</em> 된다. 따라서 콜백 코드에서 예외가 발생할 수 있는 경우 다른 콜백을 실행하려면 이를 구조화하고 콜백 내에서 처리해야 한다.</p></div><div class="warning"><p><code>after_commit</code> 또는 <code>after_rollback</code> 콜백 내에서 실행되는 코드 자체는 트랜잭션 내에 포함되지 않는다.</p></div><div class="warning"><p>동일한 모델에서 <code>after_create_commit</code> 과 <code>after_update_commit</code> 를 모두 사용하면 정의된 마지막 콜백만 적용되고 다른 콜백은 모두 무시된다.</p></div><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class User < ApplicationRecord
after_create_commit :log_user_saved_to_db
after_update_commit :log_user_saved_to_db
private
def log_user_saved_to_db
puts 'User was saved to database'
end
end
# prints nothing
>> @user = User.create
# updating @user
>> @user.save
=> User was saved to database
</pre>
</div>
<p>create 와 update를 함께 사용하기 위한 <code>after_commit</code> 콜백 별명도 있다.</p>
<ul>
<li><code>after_save_commit</code></li>
</ul>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class User < ApplicationRecord
after_save_commit :log_user_saved_to_db
private
def log_user_saved_to_db
puts 'User was saved to database'
end
end
# creating a User
>> @user = User.create
=> User was saved to database
# updating @user
>> @user.save
=> User was saved to database
</pre>
</div>
<p>초벌번역 : 2019-10-24 시작 2019-10-25 종료</p>
<h3>피드백</h3>
<p>
이 가이드의 품질을 향상시키기 위해 여러분의 도움이 필요하다.
</p>
<p>
오타나 실제 오류를 발견시 여러분의 기여를 권고한다. 시작하려면 본 <a href="https://edgeguides.rubyonrails.org/contributing_to_ruby_on_rails.html#contributing-to-the-rails-documentation">가이드의 기여</a> 섹션을 읽어보기 바란다.
</p>
<p>
미완성된 컨텐츠나 업데이트되지 않은 내용을 발견할 수도 있다. 누락된 문서는 master 브랜치에 추가한다. 제시된 이슈들이 master 브랜치 상에서 이미 해결되었는지 여부를 확인하려면 먼저 <a href="https://edgeguides.rubyonrails.org">Edge Guides</a>를 확인한다. 스타일과 규칙에 대해서는 <a href="ruby_on_rails_guides_guidelines.html">Ruby on Rails Guides Guidelines</a>을 확인한다.
</p>
<p>
어떤 이유로든 고칠 수 있지만 직접 패치 할 수 없는 경우 <a href="https://github.com/rails/rails/issues">이슈를 새로 오픈</a>하면 된다.
</p>
<p>
그리고 마지막으로, 루비온레일스 문서에 관한 모든 논의는 <a href="https://groups.google.com/forum/#!forum/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/">Creative Commons Attribution-ShareAlike 4.0 International License</a> 를 준수한다. </p>
<p>"Rails", "Ruby on Rails", 그리고 레일스 로고는 David Heinemeier Hansson의 등록상표이다. 판권 소유.</p>
</div>
</div>
</body>
</html>