This repository was archived by the owner on Jan 7, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathajax_on_rails.html
506 lines (467 loc) · 39.8 KB
/
ajax_on_rails.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
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>Ruby on Rails Guides: AJAX on Rails</title>
<link rel="stylesheet" type="text/css" href="stylesheets/style.css" />
<link rel="stylesheet" type="text/css" href="stylesheets/print.css" media="print" />
<link rel="stylesheet" type="text/css" href="stylesheets/syntaxhighlighter/shCore.css" />
<link rel="stylesheet" type="text/css" href="stylesheets/syntaxhighlighter/shThemeRailsGuides.css" />
</head>
<body class="guide">
<div id="topNav">
<div class="wrapper">
<strong>More at <a href="http://rubyonrails.org/">rubyonrails.org:</a> </strong>
<a href="http://rubyonrails.org/">Overview</a> |
<a href="http://rubyonrails.org/download">Download</a> |
<a href="http://rubyonrails.org/deploy">Deploy</a> |
<a href="http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/overview">Code</a> |
<a href="http://rubyonrails.org/screencasts">Screencasts</a> |
<a href="http://rubyonrails.org/documentation">Documentation</a> |
<a href="http://rubyonrails.org/ecosystem">Ecosystem</a> |
<a href="http://rubyonrails.org/community">Community</a> |
<a href="http://weblog.rubyonrails.org/">Blog</a>
</div>
</div>
<div id="header">
<div class="wrapper clearfix">
<h1><a href="index.html" title="Return to home page">Guides.rubyonrails.org</a></h1>
<p class="hide"><a href="#mainCol">Skip navigation</a>.</p>
<ul class="nav">
<li><a href="index.html">홈</a></li>
<li class="index"><a href="index.html" onclick="guideMenu(); return false;" id="guidesMenu">목차</a>
<div id="guides" class="clearfix" style="display: none;">
<hr />
<dl class="L">
<dt>시작</dt>
<dd><a href="getting_started.html">레일즈 시작하기</a></dd>
<dt>모델(Models)</dt>
<dd><a href="migrations.html">레일즈 데이터베이스 마이그레이션</a></dd>
<dd><a href="active_record_validations_callbacks.html">액티브 레코드 데이터 검증(Validation)과 Callback(콜백)</a></dd>
<dd><a href="association_basics.html">액티브 레코드 Association(관계)</a></dd>
<dd><a href="active_record_querying.html">액티브 레코드 쿼리 인터페이스</a></dd>
<dt>뷰(Views)</dt>
<dd><a href="layouts_and_rendering.html">레이아웃(Layouts)과 렌더링(Rendering)</a></dd>
<dd><a href="form_helpers.html">액션 뷰 폼 핼퍼(Action View Form Helpers)</a></dd>
<dt>컨트롤러(Controllers)</dt>
<dd><a href="action_controller_overview.html">액션 컨트롤러 둘러보기</a></dd>
<dd><a href="routing.html">외부 요청에 대한 레일즈 라우팅</a></dd>
</dl>
<dl class="R">
<dt>심화내용</dt>
<dd><a href="active_support_core_extensions.html">액티브 서포트(Active Support) 확장(Core Extensions)</a></dd>
<dd><a href="i18n.html">레일즈 국제화I(nternationalization) API</a></dd>
<dd><a href="action_mailer_basics.html">액션 메일러의 기본</a></dd>
<dd><a href="testing.html">레일즈 어플리케이션 테스트하기</a></dd>
<dd><a href="security.html">레일즈 어플리케이션의 보안</a></dd>
<dd><a href="debugging_rails_applications.html">레일즈 어플리케이션 디버깅</a></dd>
<dd><a href="performance_testing.html">레일즈 어플리케이션 성능 테스트하기</a></dd>
<dd><a href="configuring.html">레일즈 어플리케이션 설정</a></dd>
<dd><a href="command_line.html">레일즈 커멘드라인 도구와 Rake 테스크</a></dd>
<dd><a href="caching_with_rails.html">레일즈를 이용한 캐싱</a></dd>
<dt>레일즈 확장하기(Extending Rails)</dt>
<dd><a href="plugins.html">레일즈 플러그인 작성의 기본</a></dd>
<dd><a href="rails_on_rack.html">렉 위의 레일즈(Rails on Rack)</a></dd>
<dd><a href="generators.html">레일즈 제너레이터(Generator) 제작과 수정</a></dd>
<dt>루비 온 레이즈에 기여하기</dt>
<dd><a href="contributing_to_ruby_on_rails.html">루비 온 레이즈에 기여하기</a></dd>
<dd><a href="api_documentation_guidelines.html">API 문서 가이드라인</a></dd>
<dd><a href="ruby_on_rails_guides_guidelines.html">루비 온 레일즈 가이드에 대한 가이드라인</a></dd>
<dt>Release Notes</dt>
<dd><a href="3_0_release_notes.html">Ruby on Rails 3.0 Release Notes</a></dd>
<dd><a href="2_3_release_notes.html">Ruby on Rails 2.3 Release Notes</a></dd>
<dd><a href="2_2_release_notes.html">Ruby on Rails 2.2 Release Notes</a></dd>
</dl>
</div>
</li>
<li><a href="contribute.html">기여하기</a></li>
<li><a href="credits.html">수고하신 분들</a></li>
</ul>
</div>
</div>
<hr class="hide" />
<div id="feature">
<div class="wrapper">
<h2><span class="caps">AJAX</span> on Rails</h2>
<p>이 안내서는 레일스에 내장되어 있는 Ajax/JavsScript 기능성을 다루고 있어서 다양하고 동적인 <span class="caps">AJAX</span> 어플리케이션을 쉽게 만들수 있게 해 줄 것입니다. 여기서 다룰 주제는 다음과 같습니다.</p>
<ul>
<li>AJAX와 관련된 기술들에 대한 간략한 소개</li>
<li>자바스크립트를 레일스방식으로 다루기: Rails helpers, <span class="caps">RJS</span>, Prototype and script.aculo.us</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="#ajax">안녕, <span class="caps">AJAX</span> – 간략한 소개</a><ul><li><a href="#ajax"><span class="caps">AJAX</span></a></li> <li><a href="#dom"><span class="caps">DOM</span> 객체</a></li> <li><a href="#standard-html-communication-vs-ajax">Standard <span class="caps">HTML</span> communication vs <span class="caps">AJAX</span></a></li></ul></li><li><a href="#">내장 레일스 헬퍼메소드</a><ul><li><a href="#ajax-link_to_remote">전형적인 <span class="caps">AJAX</span> 레일스 헬퍼메스드: link_to_remote</a></li> <li><a href="#ajax"><span class="caps">AJAX</span> 폼</a></li> <li><a href="#">엘리먼트에 이벤트 핸들러를 등록하기</a></li> <li><a href="#">주기적으로 함수 호출하기</a></li> <li><a href="#">기타 함수</a></li></ul></li><li><a href="#rjs">레일스 방식(<span class="caps">RJS</span>)으로 자바스크립트 코딩하기</a><ul><li><a href="#rjs">RJS를 사용하지 않고 자바스크립트 코딩하기</a></li> <li><a href="#rjs">인라인 <span class="caps">RJS</span></a></li> <li><a href="#rjs"><span class="caps">RJS</span> 템플릿</a></li> <li><a href="#rjs-reference"><span class="caps">RJS</span> Reference</a></li></ul></li><li><a href="#i-want-my-yellow-thingy-script-aculo-us">I Want my Yellow Thingy: Script.aculo.us의 간단한 개요</a><ul><li><a href="#">소개</a></li> <li><a href="#">시각적 효과</a></li> <li><a href="#drag-and-drop">Drag and Drop</a></li></ul></li><li><a href="#">자바스크립트 테스트하기</a></li></ol></div>
</div>
</div>
<div id="container">
<div class="wrapper">
<div id="mainCol">
<h3 id="ajax">1 안녕, <span class="caps">AJAX</span> – 간략한 소개</h3>
<p>‘show me the code’형의 사람이라면 이 부분을 건너띠고 <span class="caps">RJS</span> 부분으로 이동하고 싶어 할 수 있습니다. 그러나, 이 부분을 읽어 볼 것을 정말로 권하는데, 레일스에서 Ajax를 잘 이해하려면 여기서 언급되는 DOM의 기본개념, http 요청하는 방법, 그리고 기타 다른 토픽들이 필요할 것이기 때문입니다.</p>
<h4 id="ajax">1.1 <span class="caps">AJAX</span></h4>
<p>(= <tt>A</tt> synchronous <tt>Ja</tt> vaScript <tt> </tt>X+ ML)</p>
<p>Ajax의 기본 용어설명, 웹어플리케이션을 만드는 새로운 방식</p>
<h4 id="dom">1.2 <span class="caps">DOM</span> 객체</h4>
<p><span class="caps">DOM</span> 의 기본개념, <span class="caps">DOM</span> 이 만들어진 방법, <span class="caps">DOM</span> 의 속성, 특징, <span class="caps">DOM</span> 이 <span class="caps">AJAX</span> 의 핵심인 이유</p>
<h4 id="standard-html-communication-vs-ajax">1.3 Standard <span class="caps">HTML</span> communication vs <span class="caps">AJAX</span></h4>
<p>통상적인 요청과 AJAX요청의 차이점, 레일스에서 <span class="caps">AJAX</span> 를 이해하는데 있어서의 이러한 차이점의 중요성(다음 섹션에 언급되는 *_remote 헬퍼메소드와 연관됨)</p>
<p>h3(#). 2 내장 레일스 헬퍼메소드</p>
<p>레일스의 기본 자바스크립트 프레임워크는 <a href="http://www.prototypejs.org">Prototype</a> 입니다. Prototype 은 일반적으로 사용할 수 있는 자바스크립트 프레임워크로서 <span class="caps">DOM</span> 객체 조작과 <span class="caps">AJAX</span> 를 제공하며, 그외에도 유틸리티 함수로부터 객체지향적 구조에 이르는 자바스크립트 기능을 제공해 줌으로써 동적인 웹어프리케이션을 쉽게 개발할 수 있도록 하기 위해 만들어 졌습니다. Prototype 은 특정언어를 위해서 만들어진 것이 아니기 때문에, 이와 관련된 다수의 헬퍼메소드를 레일스가 제공해서 Prototype이 레일스 뷰 파일들과 매끄럽게 통합될 수 있도록 해줍니다.</p>
<p>이러한 헬퍼메소드에 접근하기 위해서 해야 할 것은 대개는 application.html.erb와 같은 웹어플리케이션의 최상위 레이아웃 파일에 Prototype 프레임워크를 아래와 같이 포함시키는 것입니다.</p>
<notextile>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
javascript_include_tag 'prototype'
</pre>
</div>
</notextile>
<p>이제 레일스 어플리케이션에 AJAX에 대한 사랑을 더해 줄 준비가 된 것입니다.</p>
<h4 id="ajax-link_to_remote">2.1 전형적인 <span class="caps">AJAX</span> 레일스 헬퍼메스드: link_to_remote</h4>
<p>아마도 가장 많이 사용하는 헬퍼메소드인 <tt>link_to_remote</tt> 로부터 시작해 봅시다. 관련 도큐먼트에 기록된 것을 볼 대 이 헬퍼메소드는 재미있는 특징을 가지고 있는데, 이 헬퍼메소드로 넘겨지는 옵션들은 모든 <span class="caps">AJAX</span> 헬퍼메소드들에서도 공유하게 된다는 것입니다. 따라서 이 헬퍼메소드의 옵션과 작동 기전을 배우게 되면 다른 헬퍼메소드를 사용하는데 도움이 될 것입니다.</p>
<p><tt>link_to_remote</tt> 함수는 표준 <tt>link_to</tt> 헬퍼메소드와 그 특징이 같습니다. :</p>
<notextile>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
def link_to_remote(name, options = {}, html_options = nil)
</pre>
</div>
</notextile>
<p>그리고 아래에 link_to_remote 헬퍼메소드에 대한 간단한 예제가 있습니다.</p>
<notextile>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
link_to_remote "Add to cart",
:url => add_to_cart_url(product.id),
:update => "cart"
</pre>
</div>
</notextile>
<ul>
<li>제일 처음에 있는 매개변수는 문자열인데, 웹페이지에 나타나는 링크의 텍스트입니다.</li>
</ul>
<ul>
<li>두번째 매개변수는 <tt>options</tt> 해쉬이며, AJAX에 관련된 기능을 가질 때 가장 재미있는 부분입니다.
<ul>
<li><strong>:url</strong> 이것은 가장 간단한 리모드 링크를 만들기 위해 반드시 필요한 매개변수입니다. 기술적으로는, :url 매개변수 없이 빈 해쉬를 넘길 수 있지만, 이런 경우에는 프로그래머의 의도와는 상관없이 <span class="caps">POST</span> 요청시에 사용되는 주소가 현재의 주소가 될 것입니다. 이 URl 주소에는 <span class="caps">AJAX</span> 액션 핸들러의 위치를 지정해 줍니다. 대개 이 URL에는 레일스REST 뷰 헬퍼메소드를 이용해서 지정하게 되지만, <tt>url_for</tt> 형태로 지정할 수도 있습니다.</li>
<li><strong>:update</strong> 기본적으로 서버로부터의 응답을 웹페이지상에 보여지기 하는데는 2가지 방법이 있습니다. 하나는 RJS에 관련된 사항하고 이것은 다음 장에서 언급할 것입니다. 다른 하나는 업데이트하고자는 하는 엘리먼트의 <span class="caps">DOM</span> 아이디 값을 지정하는 것입니다. 위의 예제에서는 이것에 대한 가장 간단한 방법을 소개하지만, 서버가 웹페이지에 표시될 에러 메시지로 응답을 할 때 문제가 생기게 됩니다. 그러나 레일스는 이러한 상황에 대한 해결방법을 가지고 있습니다.</li>
</ul></li>
</ul>
<notextile>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
link_to_remote "Add to cart",
:url => add_to_cart_url(product),
:update => { :success => "cart", :failure => "error" }
</pre>
</div>
</notextile>
<p>서버가 200번으로 응답할 때 위의 예제는 이전의 간단한 예제와 같은 결과를 보여 줄 것입니다. 그러나, 에러가 발생할 경우에는 “cart” 엘리먼트가 아니라 “error” 아이디를 가지는 <span class="caps">DOM</span> 엘리먼트가 업데이트 됩니다.</p>
<ul>
<li><strong>position</strong> : 기본적으로(이전 예제와 같이 이 옵션을 명시하지 않은 때), 서버로부터의 응답은 명시된 <span class="caps">DOM</span> 아이디를 가진 엘리먼트에 표시되어 이전 값이 있을 경우 이를 대체하게 됩니다. 경우에 따라 해당 엘리먼트의 원래의 값을 변경하기 않도록 이러한 동작을 변경하기를 원할 수 있습니다. 여기서 문제는 새로운 값을 어디에 둘 것이냐 입니다. 바로 이때 <tt>position</tt> 매개변수를 지정해서 위치를 지정할 수 있으며, 4가지 옵션을 가질 수 있습니다.
<ul>
<li><tt>:before</tt> : 서버응답 내용을 대상 엘리먼트 직전에 삽입합니다. 더 정확하게 말하면, 서버응답으로부터 텍스트 노드를 만들어서 대상 엘리먼트의 직전 형제노드로 삽입합니다.</li>
<li><tt>:after</tt> : <tt>:before</tt> 와 비슷한 동작을 합니다만, 이 경우에는 대상 엘리먼트 이후에 서버응답이 삽입됩니다.</li>
<li><tt>:top</tt> : 텍스트를 원본 내용 이전에 있는 대상 엘리먼트로 삽입합니다. 대상 엘리먼트가 비어 있는 경우에는 <tt>:position</tt> 값을 전혀 설정하지 않은 상태와 동일하게 됩니다.</li>
<li><tt>:bottom</tt> : <tt>:top</tt> 의 반대 옵션으로 서버응답이 대상 엘리먼트의 원본 내용 다음에 삽입됩니다.</li>
</ul></li>
</ul><p><tt>:bottom</tt> 옵션을 이용하는 전형적인 예는 기존 목록에 <li> 엘리먼트를 새로 추가하는 것입니다.</p>
<notextile>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
link_to_remote "Add new item",
:url => items_url,
:update => 'item_list',
:position => :bottom
</pre>
</div>
</notextile>
<ul>
<li><strong>:method</strong> : 뷰 템블릿에 원격 링크를 추가할 대 가장 기본적으로 <span class="caps">POST</span> 요청을 하게 되어 이것이 디폴트 동작이 되는 것입니다. 그러나, 경우에 따라 특정 내용을 업데이트(<span class="caps">PUT</span>)하거나 삭제(<span class="caps">DELETE</span>)하고자 할 때 <tt>:method</tt> 옵션을 이용하여 명시할 수 있습니다. 특정 목록에서 하나의 항목을 삭제하기 위한 전형적인 <span class="caps">AJAX</span> 링크에 대한 예를 보겠습니다.</li>
</ul><notextile>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
link_to_remote "Delete the item",
:url => item_url(item),
:method => :delete
</pre>
</div>
</notextile>
<p>주의할 것은, 디폴트 동작(<span class="caps">POST</span>)을 변경하지 않을 경우 위의 코드는 삭제보다는 생성(create) 동작으로 작동하게 될 것입니다.</p>
<ul>
<li><strong>JavaScript filters</strong> : 자바스크립트 코드로 감싸게 되면 원격 호출을 변경할 수 있습니다. 예를 들어 이전 예제에서, 특정 링크를 없애고자 할 때, 유저에게 간단한 텍스트 박스를 보여주어 확인을 요구할 수 있습니다. 이것은 전형적인 예로서 이 옵션을 이용하여 수행할 수 있습니다. 하나씩 알아보도록 하겠습니다.
<ul>
<li><tt>:confirm</tt> => <tt>msg</tt> : 자바스크립트 확인 대화창을 띄워 <tt>msg</tt> 를 보여줍니다. 유저가 ’OK’를 선택하면 요청 작업이 진행되고 그렇지 않으면 취소됩니다.</li>
<li><tt>:condition</tt> => <tt>code</tt> : 논리값을 반환하는 <tt>code</tt> 를 실해하여 참이면 작업을 진행하고 그렇지 않으면 취소합니다.</li>
<li><tt>:before</tt> => <tt>code</tt> : 요청을 진행하기 직전에 <tt>code</tt> 를 실행합니다. 해당 코드의 결과는 호출에 영향을 미치지 않습니다. 진행상황을 표시하기 위해서 흔히 사용되며 다음 예제에서 이러한 동작을 알 수 있습니다.</li>
<li><tt>:after</tt> => <tt>code</tt> : 요청을 실행한 후에 <tt>code</tt> 를 평가하게 됩니다. 다음 섹션에서 다루게 되겠지만 이것은 <tt>:success</tt> 나 <tt>:complet</tt> 콜백과는 다릅니다. 이것들은 요청이 완료된 후에 실행되지만, <tt>:after</tt> 로 넘겨지는 코드는 원격 호출 된 직후에 실행된다는 것에 주목해야 합니다. 일반적인 예를 들면 웹페이지의 엘리먼트를 사용하지 못하게 하거나 요청이 완료되는 시점에서 더이상 동작을 하지 못하도록 할 경우입니다.</li>
<li><tt>:submit</tt> => <tt>dom_id</tt> : 이 옵션은 <tt>link_to_remote</tt> 헬퍼메소드에 해당되지 않지만 모든 것을 언급한다는 의미에서 여기서 다루기로 하겠습니다. 디폴트로, 유저가 서밋하는 폼 엘리먼트의 상위 엘리먼트는 현재의 폼이 됩니다. 이 때 디폴트 동작을 변경하고자 할 때 이 옵션을 사용하면 됩니다. 이 옵션을 지정하게 되면, <span class="caps">DOM</span> 아이디값 <tt>dom_id</tt> 을 지정해서 상위 엘리먼트를 변경할 수 있게 됩니다.</li>
<li><tt>:with</tt> > <tt>code</tt> : <tt>code</tt> 값 안에 할당된 자바스크립트 코드가 평가된 후 요청된 URL에 매개변수(들)로 추가됩니다. 그러므로 <tt>code</tt> 값은 유효한 <span class="caps">URL</span> 쿼리문자열을 반환하게 됩니다(like “item_type=8” or “item_type=8&sort=true”). 대개는 웹페이시에서 값들을 얻게 됩니다. 자 예제를 보겠습니다.</li>
</ul></li>
</ul><notextile>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
link_to_remote "Update record",
:url => record_url(record),
:method => :put,
:with => "'status=' + 'encodeURIComponent($('status').value) + '&completed=' + $('completed')"
</pre>
</div>
</notextile>
<p>이 코드는 웹페이지내의 ’status’와 ‘compeleted’ <span class="caps">DOM</span> 아이디를 가지는 엘리먼트로부터 가져 온 2개의 매개변수를 레일스가 만들어 주는 표준 URL에 추가하여 원격 링크를 만들어 줍니다.</p>
<ul>
<li><strong>Callbacks</strong> : <span class="caps">AJAX</span> 호출은 보통 비동기화 되어 일어나지만, 그 이름이 암시하는 바와 같이 (반드시 그런 것은 아니지만, 마지막 옵션인 <tt>:type</tt> 을 설정하여 요청을 동기화할 수 있습니다) 특정 요청이 시작된 후 해당 요청과 통신할 수 있는 유일한 방법은 콜백을 지정하는 것입니다. 재량에 따라 6개의 옵션을 있을 수 있습니다(모드 가능성 있는 응답 형태를 계산해 보면 508개나 되지만 언급한 6개만이 가장 자주 사용되어 상수로 정의하게 되었습니다).
<ul>
<li><tt>:loading:</tt> => <tt>code</tt> : 요청이 데이타를 받는 중에 있지만 완료되지 않은 상태입니다.</li>
<li><tt>:loaded:</tt> => <tt>code</tt> : 요청으로부터 데이타 이동이 완료되었지만 아직 처리되지 못하여 반환되지 않은 상태입니다.</li>
<li><tt>:interactive:</tt> => <tt>code</tt> : <tt>:loaded</tt> 직후 단계로서 데이타 이동이 완료되어 처리된 상태입니다.</li>
<li><tt>:success:</tt> => <tt>code</tt> : 서버로 데이타 이동이 완료되어 처리된 후에 “200 OK” 응답을 보낸 상태입니다.</li>
<li><tt>:failure:</tt> => <tt>code</tt> : 서버로 데이타 이동이 완료되어 치리된 후에 “200 OK” 외의 값으로 응답을 보낸 상태입니다.(대개는 404 또는 500 값이지만 일반적으로 100에서 509까지의 상태 코드값을 가질 수 있습니다)</li>
<li><tt>:complete:</tt> => <tt>code</tt> : 이전 두개의 옵션을 합한 상태입니다. 즉, 요청이 완료되어 데이타가 분석되고 상태 코드값을 반환한 상태입니다(상태 코드값은 어떠한 값이어도 됩니다).</li>
<li>기타 다른 상태 코드값(100-509) : 404 와 같은 기타 <span class="caps">HTTP</span> 상태 코드값을 점검할 경우에는 상태 코드값을 숫자로 사용하면 됩니다.</li>
</ul></li>
</ul><notextile>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
link_to_remote "Add new item",
:url => items_url,
:update => "item_list",
404 => "alert('Item not found!')"
</pre>
</div>
</notextile>
<p>가장 자주 사용하는 콜백인 <tt>:success</tt>, <tt>:failure</tt>, <tt>:complete</tt> 가 동작하는 전형적인 예제를 봅시다.</p>
<notextile>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
link_to_remote "Add new item",
:url => items_url,
:update => "item_list",
:before => "$('progress').show()",
:complete => "$('progress').hide()",
:success => "display_item_added(request)",
:failure => "display_error(request)"
</pre>
</div>
</notextile>
<ul>
<li><strong>:type</strong> : 어떤 분명치 않은 이유로 해서 요청을 동기화하고 싶을 때(요청이 처리되고 상태 값을 반환하지 않은 상태에서 브라우져를 사용할 수 없게 해야 하는 경우) 이 옵션을 <tt>:synchronous</tt> 로 설정해서 이용할 수 있습니다.</li>
</ul><ul>
<li>마지막으로 <tt>html_options</tt> 매개변수를 이용해서, 최종적으로 만들어지는 태그에 <span class="caps">HTML</span> 속성을 추가할 수 있습니다. 이것은 <tt>link_to</tt> 헬퍼메소드의 동일한 매개변수와 같이 동작을 합니다. 그러나 <tt>href</tt> 와 <tt>onclick</tt> 매개변수에 대해서는 재미있는 부대효과가 있습니다.
<ul>
<li><tt>href</tt> 매개변수를 지정할 경우, 클라이언트 브라우져에서 자바스크립트가 작동하지 않더라도 <span class="caps">AJAX</span> 링크가 멋지게 깨지면서 링크는 지정한 주소로 연결이 가능하게 됩니다.</li>
<li><tt>link_to_remote</tt> 는 링크의 onclick 핸들러에 원격 콜을 지정해 두게 되면 <span class="caps">AJAX</span> 동작을 하게 됩니다. <tt>html_options[:onclick]</tt> 을 설정하면 디폴트 동작을 변경하게 되므로 주의를 기울려야 합니다.</li>
</ul></li>
</ul>
<p>이제 <tt>link_to_remote</tt> 대한 설명을 마칩니다. 하나의 헬퍼함수에 대해서 소화하기에는 많은 양이지만 기억할 것은 이 옵션들은 레일스 뷰 헬퍼메소들에 대해서 일반적으로 적용할 수 있어서 다음 섹션에서 차이점과 추가된 매개변수들에 대해서 알아 보도록 하겠습니다.</p>
<h4 id="ajax">2.2 <span class="caps">AJAX</span> 폼</h4>
<p>Prototype 헬퍼메소드를 이용해서 뷰템플릿에 <span class="caps">AJAX</span> 폼을 추가하는데는 3가지 방법이 있습니다. 약간씩의 차이점이 있지만 결국은 같은 목적을 위한 것입니다. 즉, 표준 <span class="caps">HTTP</span> 요청/응답 주기를 이용해서 서밋(submit)하는 대신에, 웹페이지를 다시 로딩하지 않고 비동기적으로 서밋하게 됩니다. 이러한 메소드는 다음과 같습니다.</p>
<ul>
<li><tt>remote_form_for</tt> (and it’s alias <tt>form_remote_for</tt>) 는 매개변수로서 하나의 리소스, 즉, 모델이나 리소스배열(중첩리소스)을 사용하기 때문에 3가지 방법 중에 가장 밀접하게 레일스에 연결됩니다.</li>
<li><tt>form_remote_tag</tt> 는 백그라운드에서 폼 데이터를 시리얼로 보냄으로서써 폼을 AJAX화 합니다.</li>
<li><tt>submit_to_remote</tt> 와 <tt>button_to_remote</tt> 는 이전 두개의 방법보다는 더 자주 사용되지는 않습니다. <span class="caps">AJAX</span> 폼을 만들기보다는 버튼이나 input 컴포넌트를 추가해 줍니다.</li>
</ul>
<p>작동되는 것은 하나씩 알아 보도록 합시다!</p>
<h5 id="remote_form_for">2.2.1 <tt>remote_form_for</tt></h5>
<h5 id="form_remote_tag">2.2.2 <tt>form_remote_tag</tt></h5>
<h5 id="submit_to_remote">2.2.3 <tt>submit_to_remote</tt></h5>
<p>h4(#). 2.3 엘리먼트에 이벤트 핸들러를 등록하기</p>
<h5 id="observe_field">2.3.1 <tt>observe_field</tt></h5>
<h5 id="observe_form">2.3.2 <tt>observe_form</tt></h5>
<p>h4(#). 2.4 주기적으로 함수 호출하기</p>
<h5 id="periodically_call_remote">2.4.1 <tt>periodically_call_remote</tt></h5>
<p>h4(#). 2.5 기타 함수</p>
<h5 id="remote_function">2.5.1 <tt>remote_function</tt></h5>
<h5 id="update_page">2.5.2 <tt>update_page</tt></h5>
<h3 id="rjs">3 레일스 방식(<span class="caps">RJS</span>)으로 자바스크립트 코딩하기</h3>
<p>지난 섹션에서, 서버에 몇가지 <span class="caps">AJAX</span> 요청을 보내고 ( <tt>:update</tt> 옵션을 이용해서) 웹페이지에 HTML응답을 삽입한 바 있습니다. 그러나, 때로는 좀 더 복잡한 동작을 웹페이지에 적용해야 할 경우가 필요한데, 바로 이런 경우에 자바스크립트나 RJS를 이용할 수 있습니다. 두 경우 모두에서 서버로 자바스크립트 명령을 보내게 되는데, 전자의 경우에는 바닐라 자바스크립트를, 후자의 경우는 레일스로 코딩을 하고 잠시 레일스가 자바스크립트를 만들 때까지 기다리게 됩니다. 그것은 기본적으로 RJS가 루비 DSL이어서 레일스 코드내에 자바스크립트 코드를 삽입하기 때문입니다.</p>
<h4 id="rjs">3.1 RJS를 사용하지 않고 자바스크립트 코딩하기</h4>
<p>먼저 서버로 자바스크립트를 수동으로 보내는 방밥을 알아볼 것입니다. 실제로는 이런 경우는 없겠지만 어떤 상황이 일어나고 있는지를 이애해 두는 것은 재미있는 일입니다.</p>
<notextile>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
def javascript_test
render :text => "alert('Hello, world!')",
:content_type => "text/javascript"
end
</pre>
</div>
</notextile>
<p>(주의: 바로 위의 메소드를 점검하기 위해서는, <tt>javascript_test</tt> 액션으로 연결되는 <tt>:url</tt> 옵션을 설정해서 <tt>link_to_remote</tt> 를 만들어야 합니다.)</p>
<p>위의 메소드에서는 헤더변수인 Content-Type을 지정해서 브라우져가 전송되는 텍스트를 단순한 텍스트로 보지 주지 않고 자바스크립트 디폴트 동작을 하도록 지시하게 됩니다.</p>
<h4 id="rjs">3.2 인라인 <span class="caps">RJS</span></h4>
<p>언급했던 바와 같이, RJS의 목적은 레일스가 자동으로 자바스크립트로 변환시켜주는 루비 코딩을 하는 것입니다. 위의 예제는 너무 루비식이 아니라서 레일스식으로 어떻게 코딩하는 알아 보겠습니다.</p>
<notextile>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
def javascript_test
render :update do |page|
page.alert "Hello from inline RJS"
end
end
</pre>
</div>
</notextile>
<p>위의 코드 부분은 이전 섹션의 것과 정확히 동일하지만 훨씬 우아하게 코딩한 것입니다. 헤더부분에 대해서 걱정할 필요없어서 자바스크립트 코드를 문자열로 넣을 필요가 없습니다. <tt>render</tt> 의 첫번째 매개변수가 <tt>:update</tt> 일 경우, 레일스는 블록에서 하나의 매개변수를 필요로 합니다. 여기서는 <tt>page</tt> 가 이에 해당되며 전통적인 명명규칙을 따르며 <a href="http://api.rubyonrails.org/classes/ActionView/Helpers/PrototypeHelper/JavaScriptGenerator/GeneratorMethods.html">JavaScriptGenerator</a> 객체의 인스턴스입니다. 이름에서 알 수 있듯이, JavaScriptGenerator는 로비 코드에서 자바스크립트 코드를 만들어 냅니다. <tt>page</tt> 인스턴스에 대해서 메소드 호출을 여러번 할 수 있습니다. 모두 자바스크립트로 변환되어 적절한 Content Type, 즉, “text/javascript”형태로써 서버로 보내지게 됩니다.</p>
<h4 id="rjs">3.3 <span class="caps">RJS</span> 템플릿</h4>
<p>인라인 RJS가 한줄 이상인 경우와 같이 컨트롤러가 뷰 코드로 너저분해지기를 원치 않는다면, <span class="caps">RJS</span> 코드를 뷰 템플릿 파일로 옮길 수 있습니다. 이 때 <span class="caps">RJS</span> 템플릿은 <tt>/app/views/</tt> 디렉토리로 이동해야 하며, 해당 컨트롤러의 <tt>.html.erb</tt> 이나 다른 뷰 파일 형태, 대개는 <tt>js.rjs</tt> 파일 형태를 가지게 됩니다.</p>
<p>위의 예제를 다시 작성하면, 액션 코드부분을 비워두고 <tt>javascript_test.js.rjs</tt> 라는 이름으로 <span class="caps">RJS</span> 템플릿 파일을 만들고 아래의 코드를 폼함시켜 둡니다.</p>
<notextile>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
page.alert "Hello from inline RJS"
</pre>
</div>
</notextile>
<h4 id="rjs-reference">3.4 <span class="caps">RJS</span> Reference</h4>
<p>이 섹션에서는 RJS가 제공하는 메소드를 알아 보겠습니다.</p>
<h5 id="javascriptgenerator">3.4.1 JavaScriptGenerator 메소드</h5>
<h6 id="dom">3.4.1.1 <span class="caps">DOM</span> 엘리먼트 다루기</h6>
<p><tt>page</tt> JavascriptGenerator 인스턴스를 이용해서 한번 여러 개의 엘리먼트를 다룰 수 있습니다. 실제 코드를 보도록 하겠습니다.</p>
<notextile>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
page.show :div_one, :div_two
page.hide :div_one
page.remove :div_one, :div_two, :div_three
page.toggle :other_div
</pre>
</div>
</notextile>
<p>위의 메소드(<tt>show</tt>, <tt>hide</tt>, <tt>remove</tt>, <tt>toggle</tt>)는 Prototype과 동일한 메소드와 문법구조를 가집니다. 이 때 적어도 한개 이상의 <span class="caps">DOM</span> 아이디를 매개변수로 넘겨주어야 합니다.</p>
<p>h6(#). 3.4.1.2 컨텐츠 삽입과 교체</p>
<p><tt>insert_html</tt> 메소드를 사용해서 특정 웹페이지 상의 한 엘리먼트에 컨텐츠를 삽입할 수 있습니다.</p>
<notextile>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
page.insert_html :top, :result, '42'
</pre>
</div>
</notextile>
<p>두번째 매개변수의 <span class="caps">DOM</span> 아이디를 가진 엘리먼트의 상대적인 위치를 첫번째 매개변수로 지정해서 새로운 컨텐츠를 넘기게 됩니다.</p>
<p>상대적인 위치는 다음의 4가지 값 중에 하나를 가질 수 있습니다.</p>
<ul>
<li><tt>:before</tt> : 대상 엘리먼트 직전에 서버 응답 텍스트를 삽입합니다.</li>
<li><tt>:after</tt> : 대상 엘리먼트 직후에 서버 응답 텍스트를 삽입합니다.</li>
<li><tt>:top</tt> : 대상 엘리먼트의 원본 직전에 텍스트를 삽입합니다.</li>
<li><tt>:bottom</tt> (<tt>:top</tt> 의 반대 옵션) : 대상 엘리먼트의 원본 직후에 응답을 삽입합니다.</li>
</ul><p>세번째 매개변수는 문자열이거나 ActionView::Base#render 에 넘겨주는 해쉬형태의 옵션일 수 있습니다. 예를 들면 …</p>
<notextile>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
page.insert_html :top, :result, :partial => "the_answer"
</pre>
</div>
</notextile>
<p><tt>replace_htmel</tt> 메소드를 이용해서 특정 엘리먼트의 내용(innerHTML)을 교체할 수 있습니다. 유일한 차이점이라면 새로운 내용이 위치한 곳이 분면하기 대문에 위치 매개변수가 필요없다는 것입니다. 그래서 <tt>replace_html</tt> 은 2개의 인수만 필요하며, 이들 인수는 변경하고자 하는 엘리먼트의 <span class="caps">DOM</span> 아이디와 ActionView::Base#render로 넘겨주는 문자열이나 해쉬형의 옵션입니다.</p>
<p>h6(#). 3.4.1.3 실행지연</p>
<p><tt>dealy</tt> 이용하여 코드블럭의 실행을 지연시킬 수 있습니다.</p>
<notextile>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
page.delay(10) { page.alert('Hey! Just waited 10 seconds') }
</pre>
</div>
</notextile>
<p><tt>delay</tt> 는 초단위의 지연시간과 지정 시간만큼 지연해서 실행할 코드블럭을 매개변수로 받습니다. 블럭에 지정된 코드만이 지연되고 <tt>page.delay</tt> 라인 이후에 오는 모든 코드들은 즉작적으로 실행됩니다.</p>
<p>h6(#). 3.4.1.4 웹페이지 다시 로딩하기와 리디렉트하기</p>
<p><tt>reload</tt> 메소드를 이용하여 웹페이지를 다시 로드할 수 있습니다.</p>
<notextile>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
page.reload
</pre>
</div>
</notextile>
<p>AJAX를 사용할 때, 표준 <tt>redirect_to</tt> 컨트롤러 메소드를 사용할 수 없습니다. 대신에 <tt>page</tt> 의 인트턴스 메소드인 동일한 이름을 가진 <tt>redirect_to</tt> 를 사용해야 합니다.</p>
<notextile>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
page.redirect_to some_url
</pre>
</div>
</notextile>
<p>h6(#). 3.4.1.5 원하는 자바스크립트를 생성하기</p>
<p>때때로 RJS의 강력한 기능에도 불구하고 모든 것을 다할 수 없습니다. 그러나 여전히 순수 자바스크립트 코딩을 하고 싶지 않을 경우에, 멋진 대안이 있습니다. <tt><<</tt>, <tt>assign</tt> 그리고 <tt>call</tt> 메소드를 사용하는 것입니다.</p>
<notextile>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
page << "alert('1+1 equals 3')"
</pre>
</div>
</notextile>
<p><tt><<</tt> 를 이용해서 문자열안에 자바스크립트를 넘겨 주어 실행할 수 있습니다. 위의 코드는 다음 코드와 동일합니다.</p>
<notextile>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
page.assign :result, 3
page.call :alert, '1+1 equals ' + result
</pre>
</div>
</notextile>
<p><tt>assign</tt> 은 그냥 변수에 값을 할당합니다. <tt>call</tt> 는 <tt><<</tt> 와 비슷하지만 약간 다른 문법을 사용합니다. 첫번째 매개변수는 호출하려는 함수의 이름이고, 다음에 오는 매개변수 리스트는 함수의 매개변수로 넘겨집니다.</p>
<p>h6(#). 3.4.1.6 클랙스 프록시</p>
<p>h5(#). 3.4.2 엘리먼트 프록시</p>
<p>h5(#). 3.4.3 컬렉션 프록시</p>
<h5 id="rjs">3.4.4 <span class="caps">RJS</span> 헬퍼메소드</h5>
<h3 id="i-want-my-yellow-thingy-script-aculo-us">4 I Want my Yellow Thingy: Script.aculo.us의 간단한 개요</h3>
<p>h4(#). 4.1 소개</p>
<p>h4(#). 4.2 시각적 효과</p>
<h4 id="drag-and-drop">4.3 Drag and Drop</h4>
<p>h3(#). 5 자바스크립트 테스트하기</p>
<p>자바스크립트 테스트하기란 말은 마크 트웨인의 "Classic"이란 책을 생각나게 합니다. "클래식은 모든 사람이 이미 읽은 책이기를 바라지만 어느 누구도 읽고 싶어하지 않습니다. 자바스크립트 테스트하기도 비슷합니다. 즉, 모두가 자바스크립트 테스트하기를 원하지만 너무 지루하고 복잡하여 많은 개발자들이 하지 않는다 것입니다. 이에 대한 툴들이 많이 나오고 있고 누구나가 인정하는 최상의 방법이 없지만 다음과 같이 시도하고 있습니다.</p>
<ul>
<li>(Fire)Watir</li>
<li>Selenium</li>
<li>Celerity/Culerity</li>
<li>Cucumber+Webrat</li>
<li>Mention stuff like screw.unit/jsSpec</li>
</ul>
<p>노트 남기기 : RailsConf JS testing video 확인하기</p>
<h3>Feedback</h3>
<p>
You're encouraged to help in keeping the quality of this guide.
</p>
<p>
If you see any typos or factual errors you are confident to
patch, please clone <a href="https://github.com/lifo/docrails">docrails</a>
and push the change yourself. That branch of Rails has public write access.
Commits are still reviewed, but that happens after you've submitted your
contribution. <a href="https://github.com/lifo/docrails">docrails</a> is
cross-merged with master periodically.
</p>
<p>
You may also find incomplete content, or stuff that is not up to date.
Please do add any missing documentation for master. Check the
<a href="ruby_on_rails_guides_guidelines.html">Ruby on Rails Guides Guidelines</a>
for style and conventions.
</p>
<p>
Issues may also be reported in <a href="https://github.com/lifo/docrails/issues">Github</a>.
</p>
<p>And last but not least, any kind of discussion regarding Ruby on Rails
documentation is very welcome in the <a href="http://groups.google.com/group/rubyonrails-docs">rubyonrails-docs mailing list</a>.
</p>
</div>
</div>
</div>
<hr class="hide" />
<div id="footer">
<div class="wrapper">
<p>This work is licensed under a <a href="http://creativecommons.org/licenses/by-sa/3.0/">Creative Commons Attribution-Share Alike 3.0</a> License</p>
<p>"Rails", "Ruby on Rails", and the Rails logo are trademarks of David Heinemeier Hansson. All rights reserved.</p>
</div>
</div>
<script type="text/javascript" src="javascripts/guides.js"></script>
<script type="text/javascript" src="javascripts/syntaxhighlighter/shCore.js"></script>
<script type="text/javascript" src="javascripts/syntaxhighlighter/shBrushRuby.js"></script>
<script type="text/javascript" src="javascripts/syntaxhighlighter/shBrushXml.js"></script>
<script type="text/javascript" src="javascripts/syntaxhighlighter/shBrushSql.js"></script>
<script type="text/javascript" src="javascripts/syntaxhighlighter/shBrushPlain.js"></script>
<script type="text/javascript">
SyntaxHighlighter.all()
</script>
</body>
</html>