-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathautoloading_and_reloading_constants.html
512 lines (470 loc) · 35.2 KB
/
autoloading_and_reloading_constants.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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Autoloading and Reloading Constants (Zeitwerk Mode) — 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="Autoloading and Reloading Constants (Zeitwerk Mode) — Ruby on Rails Guides" />
<meta name="description" content="Autoloading and Reloading Constants (Zeitwerk Mode)This guide documents how autoloading and reloading works in zeitwerk mode.After reading this guide, you will know: Autoloading modes Related Rails configuration Project structure Autoloading, reloading, and eager loading Single Table Inheritance And more" />
<meta property="og:description" content="Autoloading and Reloading Constants (Zeitwerk Mode)This guide documents how autoloading and reloading works in zeitwerk mode.After reading this guide, you will know: Autoloading modes Related Rails configuration Project structure Autoloading, reloading, and eager loading Single Table Inheritance And more" />
<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>Autoloading and Reloading Constants (Zeitwerk Mode)</h2><p>This guide documents how autoloading and reloading works in <code>zeitwerk</code> mode.</p><p>After reading this guide, you will know:</p>
<ul>
<li>Autoloading modes</li>
<li>Related Rails configuration</li>
<li>Project structure</li>
<li>Autoloading, reloading, and eager loading</li>
<li>Single Table Inheritance</li>
<li>And more</li>
</ul>
<div id="subCol">
<h3 class="chapter"><img src="images/chapters_icon.gif" alt="" />Chapters</h3>
<ol class="chapters">
<li><a href="#introduction">Introduction</a></li>
<li><a href="#enabling-zeitwerk-mode">Enabling Zeitwerk Mode</a></li>
<li><a href="#project-structure">Project Structure</a></li>
<li><a href="#autoload-paths">Autoload paths</a></li>
<li><a href="#%24load-path">$LOAD_PATH</a></li>
<li>
<a href="#reloading">Reloading</a>
<ul>
<li><a href="#reloading-and-stale-objects">Reloading and Stale Objects</a></li>
</ul>
</li>
<li><a href="#eager-loading">Eager Loading</a></li>
<li><a href="#single-table-inheritance">Single Table Inheritance</a></li>
<li><a href="#customizing-inflections">Customizing Inflections</a></li>
<li><a href="#troubleshooting">Troubleshooting</a></li>
<li><a href="#rails-autoloaders">Rails.autoloaders</a></li>
<li><a href="#opting-out">Opting Out</a></li>
</ol>
</div>
</div>
</div>
<div id="container">
<div class="wrapper">
<div id="mainCol">
<h3 id="introduction"><a class="anchorlink" href="#introduction">1 Introduction</a></h3><div class="info"><p>This guide documents autoloading in <code>zeitwerk</code> mode, which is new in Rails 6. If you'd like to read about <code>classic</code> mode instead, please check <a href="autoloading_and_reloading_constants_classic_mode.html">Autoloading and Reloading Constants (Classic Mode)</a>.</p></div><p>In a normal Ruby program, dependencies need to be loaded by hand. For example, the following controller uses classes <code>ApplicationController</code> and <code>Post</code>, and normally you'd need to put <code>require</code> calls for them:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
# DO NOT DO THIS.
require "application_controller"
require "post"
# DO NOT DO THIS.
class PostsController < ApplicationController
def index
@posts = Post.all
end
end
</pre>
</div>
<p>This is not the case in Rails applications, where application classes and modules are just available everywhere:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class PostsController < ApplicationController
def index
@posts = Post.all
end
end
</pre>
</div>
<p>Idiomatic Rails applications only issue <code>require</code> calls to load stuff from their <code>lib</code> directory, the Ruby standard library, Ruby gems, etc. That is, anything that does not belong to their autoload paths, explained below.</p><h3 id="enabling-zeitwerk-mode"><a class="anchorlink" href="#enabling-zeitwerk-mode">2 Enabling Zeitwerk Mode</a></h3><p>The autoloading <code>zeitwerk</code> mode is enabled by default in Rails 6 applications running on CRuby:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
# config/application.rb
config.load_defaults "6.0" # enables zeitwerk mode in CRuby
</pre>
</div>
<p>In <code>zeitwerk</code> mode, Rails uses <a href="https://github.com/fxn/zeitwerk">Zeitwerk</a> internally to autoload, reload, and eager load. Rails instantiates and configures a dedicated Zeitwerk instance that manages the project.</p><div class="info"><p>You do not configure Zeitwerk manually in a Rails application. Rather, you configure the application using the portable configuration points explained in this guide, and Rails translates that to Zeitwerk on your behalf.</p></div><h3 id="project-structure"><a class="anchorlink" href="#project-structure">3 Project Structure</a></h3><p>In a Rails application file names have to match the constants they define, with directories acting as namespaces.</p><p>For example, the file <code>app/helpers/users_helper.rb</code> should define <code>UsersHelper</code> and the file <code>app/controllers/admin/payments_controller.rb</code> should define <code>Admin::PaymentsController</code>.</p><p>By default, Rails configures Zeitwerk to inflect file names with <code>String#camelize</code>. For example, it expects that <code>app/controllers/users_controller.rb</code> defines the constant <code>UsersController</code> because</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
"users_controller".camelize # => UsersController
</pre>
</div>
<p>The section <em>Customizing Inflections</em> below documents ways to override this default.</p><p>Please, check the <a href="https://github.com/fxn/zeitwerk#file-structure">Zeitwerk documentation</a> for further details.</p><h3 id="autoload-paths"><a class="anchorlink" href="#autoload-paths">4 Autoload paths</a></h3><p>We call <em>autoload paths</em> to the list of application directories whose contents are to be autoloaded. For example, <code>app/models</code>. Such directories represent the root namespace: <code>Object</code>.</p><div class="info"><p>Autoload paths are called <em>root directories</em> in Zeitwerk documentation, but we'll stay with "autoload path" in this guide.</p></div><p>Within an autoload path, file names must match the constants they define as documented <a href="https://github.com/fxn/zeitwerk#file-structure">here</a>.</p><p>By default, the autoload paths of an application consist of all the subdirectories of <code>app</code> that exist when the application boots ---except for <code>assets</code>, <code>javascripts</code>, <code>views</code>,--- plus the autoload paths of engines it might depend on.</p><p>For example, if <code>UsersHelper</code> is implemented in <code>app/helpers/users_helper.rb</code>, the module is autoloadable, you do not need (and should not write) a <code>require</code> call for it:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
$ bin/rails runner 'p UsersHelper'
UsersHelper
</pre>
</div>
<p>Autoload paths automatically pick any custom directories under <code>app</code>. For example, if your application has <code>app/presenters</code>, or <code>app/services</code>, etc., they are added to autoload paths.</p><p>The array of autoload paths can be extended by mutating <code>config.autoload_paths</code>, in <code>config/application.rb</code>, but nowadays this is discouraged.</p><div class="warning"><p>Please, do not mutate <code>ActiveSupport::Dependencies.autoload_paths</code>, the public interface to change autoload paths is <code>config.autoload_paths</code>.</p></div><h3 id="$load-path"><a class="anchorlink" href="#%24load-path">5 $LOAD_PATH</a></h3><p>Autoload paths are added to <code>$LOAD_PATH</code> by default. However, Zeitwerk uses absolute file names internally, and your application should not issue <code>require</code> calls for autoloadable files, so those directories are actually not needed there. You can opt-out with this flag:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
config.add_autoload_paths_to_load_path = false
</pre>
</div>
<p>That may speed legit <code>require</code> calls a bit, since there are less lookups. Also, if your application uses <a href="https://github.com/Shopify/bootsnap">Bootsnap</a>, that saves the library from building unnecessary indexes, and saves the RAM they would need.</p><h3 id="reloading"><a class="anchorlink" href="#reloading">6 Reloading</a></h3><p>Rails automatically reloads classes and modules if application files change.</p><p>More precisely, if the web server is running and application files have been modified, Rails unloads all autoloaded constants just before the next request is processed. That way, application classes or modules used during that request are going to be autoloaded, thus picking up their current implementation in the file system.</p><p>Reloading can be enabled or disabled. The setting that controls this behavior is <code>config.cache_classes</code>, which is false by default in <code>development</code> mode (reloading enabled), and true by default in <code>production</code> mode (reloading disabled).</p><p>Rails detects files have changed using an evented file monitor (default), or walking the autoload paths, depending on <code>config.file_watcher</code>.</p><p>In a Rails console there is no file watcher active regardless of the value of <code>config.cache_classes</code>. This is so because, normally, it would be confusing to have code reloaded in the middle of a console session, the same way you generally want an individual request to be served by a consistent, non-changing set of application classes and modules.</p><p>However, you can force a reload in the console executing <code>reload!</code>:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
$ bin/rails c
Loading development environment (Rails 6.0.0)
irb(main):001:0> User.object_id
=> 70136277390120
irb(main):002:0> reload!
Reloading...
=> true
irb(main):003:0> User.object_id
=> 70136284426020
</pre>
</div>
<p>as you can see, the class object stored in the <code>User</code> constant is different after reloading.</p><h4 id="reloading-and-stale-objects"><a class="anchorlink" href="#reloading-and-stale-objects">6.1 Reloading and Stale Objects</a></h4><p>It is very important to understand that Ruby does not have a way to truly reload classes and modules in memory, and have that reflected everywhere they are already used. Technically, "unloading" the <code>User</code> class means removing the <code>User</code> constant via <code>Object.send(:remove_const, "User")</code>.</p><p>Therefore, if you store a reloadable class or module object in a place that is not reloaded, that value is going to become stale.</p><p>For example, if an initializer stores and caches a certain class object</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
# config/initializers/configure_payment_gateway.rb
# DO NOT DO THIS.
$PAYMENT_GATEWAY = Rails.env.production? ? RealGateway : MockedGateway
# DO NOT DO THIS.
</pre>
</div>
<p>and <code>MockedGateway</code> gets reloaded, <code>$PAYMENT_GATEWAY</code> still stores the class object <code>MockedGateway</code> evaluated to when the initializer ran. Reloading does not change the class object stored in <code>$PAYMENT_GATEWAY</code>.</p><p>Similarly, in the Rails console, if you have a user instance and reload:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
> user = User.new
> reload!
</pre>
</div>
<p>the <code>user</code> object is instance of a stale class object. Ruby gives you a new class if you evaluate <code>User</code> again, but does not update the class <code>user</code> is instance of.</p><p>Another use case of this gotcha is subclassing reloadable classes in a place that is not reloaded:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
# lib/vip_user.rb
class VipUser < User
end
</pre>
</div>
<p>if <code>User</code> is reloaded, since <code>VipUser</code> is not, the superclass of <code>VipUser</code> is the original stale class object.</p><p>Bottom line: <strong>do not cache reloadable classes or modules</strong>.</p><h3 id="eager-loading"><a class="anchorlink" href="#eager-loading">7 Eager Loading</a></h3><p>In production-like environments it is generally better to load all the application code when the application boots. Eager loading puts everything in memory ready to serve requests right away, and it is also <a href="https://en.wikipedia.org/wiki/Copy-on-write">CoW</a>-friendly.</p><p>Eager loading is controlled by the flag <code>config.eager_load</code>, which is enabled by default in <code>production</code> mode.</p><p>The order in which files are eager loaded is undefined.</p><p>if the <code>Zeitwerk</code> constant is defined, Rails invokes <code>Zeitwerk::Loader.eager_load_all</code> regardless of the application autoloading mode. That ensures dependencies managed by Zeitwerk are eager loaded.</p><h3 id="single-table-inheritance"><a class="anchorlink" href="#single-table-inheritance">8 Single Table Inheritance</a></h3><p>Single Table Inheritance is a feature that doesn't play well with lazy loading. Reason is, its API generally needs to be able to enumerate the STI hierarchy to work correctly, whereas lazy loading defers loading classes until they are referenced. You can't enumerate what you haven't referenced yet.</p><p>In a sense, applications need to eager load STI hierarchies regardless of the loading mode.</p><p>Of course, if the application eager loads on boot, that is already accomplished. When it does not, it is in practice enough to instantiate the existing types in the database, which in development or test modes is usually fine. One way to do that is to throw this module into the <code>lib</code> directory:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
module StiPreload
unless Rails.application.config.eager_load
extend ActiveSupport::Concern
included do
cattr_accessor :preloaded, instance_accessor: false
end
class_methods do
def descendants
preload_sti unless preloaded
super
end
# Constantizes all types present in the database. There might be more on
# disk, but that does not matter in practice as far as the STI API is
# concerned.
#
# Assumes store_full_sti_class is true, the default.
def preload_sti
types_in_db = \
base_class.
select(inheritance_column).
distinct.
pluck(inheritance_column).
compact.
each(&:constantize)
types_in_db.each do |type|
logger.debug("Preloading STI type #{type}")
type.constantize
end
self.preloaded = true
end
end
end
end
</pre>
</div>
<p>and then include it in the STI root classes of your project:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
# app/models/shape.rb
require "sti_preload"
class Shape < ApplicationRecord
include StiPreload # Only in the root class.
end
# app/models/polygon.rb
class Polygon < Shape
end
# app/models/triangle.rb
class Triangle < Polygon
end
</pre>
</div>
<h3 id="customizing-inflections"><a class="anchorlink" href="#customizing-inflections">9 Customizing Inflections</a></h3><p>By default, Rails uses <code>String#camelize</code> to know which constant should a given file or directory name define. For example, <code>posts_controller.rb</code> should define <code>PostsController</code> because that is what <code>"posts_controller".camelize</code> returns.</p><p>It could be the case that some particular file or directory name does not get inflected as you want. For instance, <code>html_parser.rb</code> is expected to define <code>HtmlParser</code> by default. What if you prefer the class to be <code>HTMLParser</code>? There are a few ways to customize this.</p><p>The easiest way is to define an acronym in <code>config/initializers/inflections.rb</code>:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
ActiveSupport::Inflector.inflections(:en) do |inflect|
inflect.acronym 'HTML'
end
</pre>
</div>
<p>Doing so affects how Active Support inflects globally. That may be fine in some applications, but perhaps you prefer a more controlled technique that does not have a global effect. In such case, you can override the actual inflector in an initializer:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
# config/initializers/zeitwerk.rb
inflector = Object.new
def inflector.camelize(basename, _abspath)
basename == "html_parser" ? "HTMLParser" : basename.camelize
end
Rails.autoloaders.each do |autoloader|
autoloader.inflector = inflector
end
</pre>
</div>
<p>As you see, that still uses <code>String#camelize</code> as fallback. If you instead prefer not to depend on Active Support inflections at all and have absolute control over inflections, do this instead:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
# config/initializers/zeitwerk.rb
inflector = Class.new(Zeitwerk::Inflector) do
def camelize(basename, _abspath)
basename == "html_parser" ? "HTMLParser" : super
end
end.new
Rails.autoloaders.each do |autoloader|
autoloader.inflector = inflector
end
</pre>
</div>
<p>Please, check the <a href="https://github.com/fxn/zeitwerk#custom-inflector">Zeitwerk documentation</a> for further details.</p><h3 id="troubleshooting"><a class="anchorlink" href="#troubleshooting">10 Troubleshooting</a></h3><p>The best way to follow what the loaders are doing is to inspect their activity.</p><p>The easiest way to do that is to throw</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
Rails.autoloaders.log!
</pre>
</div>
<p>to <code>config/application.rb</code> after loading the framework defaults. That will print traces to standard output.</p><p>If you prefer logging to a file, configure this instead:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
Rails.autoloaders.logger = Logger.new("#{Rails.root}/log/autoloading.log")
</pre>
</div>
<p>The Rails logger is still not ready in <code>config/application.rb</code>, but it is in initializers:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
# config/initializers/log_autoloaders.rb
Rails.autoloaders.logger = Rails.logger
</pre>
</div>
<h3 id="rails-autoloaders"><a class="anchorlink" href="#rails-autoloaders">11 Rails.autoloaders</a></h3><p>The Zeitwerk instances managing your application are available at</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
Rails.autoloaders.main
Rails.autoloaders.once
</pre>
</div>
<p>The former is the main one. The latter is there mostly for backwards compatibility reasons, in case the application has something in <code>config.autoload_once_paths</code> (this is discouraged nowadays).</p><p>You can check if <code>zeitwerk</code> mode is enabled with</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
Rails.autoloaders.zeitwerk_enabled?
</pre>
</div>
<h3 id="opting-out"><a class="anchorlink" href="#opting-out">12 Opting Out</a></h3><p>Applications can load Rails 6 defaults and still use the classic autoloader this way:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
# config/application.rb
config.load_defaults "6.0"
config.autoloader = :classic
</pre>
</div>
<p>That may be handy if upgrading to Rails 6 in different phases, but classic mode is discouraged for new applications.</p><p><code>zeitwerk</code> mode is not available in versions of Rails previous to 6.0.</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>