Froze rails gems
[depot.git] / vendor / rails / railties / doc / guides / source / layouts_and_rendering.txt
1 Layouts and Rendering in Rails
2 ==============================
3
4 This guide covers the basic layout features of Action Controller and Action View. By referring to this guide, you will be able to:
5
6 * Use the various rendering methods built in to Rails
7 * Create layouts with multiple content sections
8 * Use partials to DRY up your views
9
10 == Overview: How the Pieces Fit Together
11
12 This guide focuses on the interaction between Controller and View in the Model-View-Controller triangle. As you know, the Controller is responsible for orchestrating the whole process of handling a request in Rails, though it normally hands off any heavy code to the Model. But then, when it's time to send a response back to the user, the Controller hands things off to the View. It's that handoff that is the subject of this guide.
13
14 In broad strokes, this involves deciding what should be sent as the response and calling an appropriate method to create that response. If the response is a full-blown view, Rails also does some extra work to wrap the view in a layout and possibly to pull in partial views. You'll see all of those paths later in this guide.
15
16 == Creating Responses
17
18 From the controller's point of view, there are three ways to create an HTTP response:
19
20 * Call +render+ to create a full response to send back to the browser
21 * Call +redirect_to+ to send an HTTP redirect status code to the browser
22 * Call +head+ to create a response consisting solely of HTTP headers to send back to the browser
23
24 I'll cover each of these methods in turn. But first, a few words about the very easiest thing that the controller can do to create a response: nothing at all.
25
26 === Rendering by Default: Convention Over Configuration in Action
27
28 You've heard that Rails promotes "convention over configuration." Default rendering is an excellent example of this. By default, controllers in Rails automatically render views with names that correspond to actions. For example, if you have this code in your +BooksController+ class:
29
30 [source, ruby]
31 -------------------------------------------------------
32 def show
33 @book = Book.find(params[:id])
34 end
35 -------------------------------------------------------
36
37 Rails will automatically render +app/views/books/show.html.erb+ after running the method. In fact, if you have the default catch-all route in place (+map.connect ':controller/:action/:id'+), Rails will even render views that don't have any code at all in the controller. For example, if you have the default route in place and a request comes in for +/books/sale_list+, Rails will render +app/views/books/sale_list.html.erb+ in response.
38
39 NOTE: The actual rendering is done by subclasses of +ActionView::TemplateHandlers+. This guide does not dig into that process, but it's important to know that the file extension on your view controls the choice of template handler. In Rails 2, the standard extensions are +.erb+ for ERB (HTML with embedded Ruby), +.rjs+ for RJS (javascript with embedded ruby) and +.builder+ for Builder (XML generator). You'll also find +.rhtml+ used for ERB templates and .rxml for Builder templates, but those extensions are now formally deprecated and will be removed from a future version of Rails.
40
41 === Using +render+
42
43 In most cases, the +ActionController::Base#render+ method does the heavy lifting of rendering your application's content for use by a browser. There are a variety of ways to customize the behavior of +render+. You can render the default view for a Rails template, or a specific template, or a file, or inline code, or nothing at all. You can render text, JSON, or XML. You can specify the content type or HTTP status of the rendered response as well.
44
45 TIP: If you want to see the exact results of a call to +render+ without needing to inspect it in a browser, you can call +render_to_string+. This method takes exactly the same options as +render+, but it returns a string instead of sending a response back to the browser.
46
47 ==== Rendering Nothing
48
49 Perhaps the simplest thing you can do with +render+ is to render nothing at all:
50
51 [source, ruby]
52 -------------------------------------------------------
53 render :nothing => true
54 -------------------------------------------------------
55
56 This will send an empty response to the browser (though it will include any status headers you set with the :status option, discussed below).
57
58 TIP: You should probably be using the +head+ method, discussed later in this guide, instead of +render :nothing+. This provides additional flexibility and makes it explicit that you're only generating HTTP headers.
59
60 ==== Using +render+ with +:action+
61
62 If you want to render the view that corresponds to a different action within the same template, you can use +render+ with the +:action+ option:
63
64 [source, ruby]
65 -------------------------------------------------------
66 def update
67 @book = Book.find(params[:id])
68 if @book.update_attributes(params[:book])
69 redirect_to(@book)
70 else
71 render :action => "edit"
72 end
73 end
74 end
75 -------------------------------------------------------
76
77 If the call to +update_attributes_ fails, calling the +update+ action in this controller will render the +edit.html.erb+ template belonging to the same controller.
78
79 WARNING: Using +render+ with +:action+ is a frequent source of confusion for Rails newcomers. The specified action is used to determine which view to render, but Rails does _not_ run any of the code for that action in the controller. Any instance variables that you require in the view must be set up in the current action before calling +render+.
80
81 ==== Using +render+ with +:template+
82
83 What if you want to render a template from an entirely different controller from the one that contains the action code? You can do that with the +:template+ option to +render+, which accepts the full path (relative to +app/views+) of the template to render. For example, if you're running code in an +AdminProductsController+ that lives in +app/controllers/admin+, you can render the results of an action to a template in +app/views/products+ this way:
84
85 [source, ruby]
86 -------------------------------------------------------
87 render :template => 'products/show'
88 -------------------------------------------------------
89
90 ==== Using +render+ with +:file+
91
92 If you want to use a view that's entirely outside of your application (perhaps you're sharing views between two Rails applications), you can use the +:file+ option to +render+:
93
94 [source, ruby]
95 -------------------------------------------------------
96 render :file => "/u/apps/warehouse_app/current/app/views/products/show"
97 -------------------------------------------------------
98
99 The +:file+ option takes an absolute file-system path. Of course, you need to have rights to the view that you're using to render the content.
100
101 NOTE: By default, if you use the +:file+ option, the file is rendered without using the current layout. If you want Rails to put the file into the current layout, you need to add the +:layout => true+ option
102
103 ==== Using +render+ with +:inline+
104
105 The +render+ method can do without a view completely, if you're willing to use the +:inline+ option to supply ERB as part of the method call. This is perfectly valid:
106
107 [source, ruby]
108 -------------------------------------------------------
109 render :inline => "<% products.each do |p| %><p><%= p.name %><p><% end %>"
110 -------------------------------------------------------
111
112 WARNING: There is seldom any good reason to use this option. Mixing ERB into your controllers defeats the MVC orientation of Rails and will make it harder for other developers to follow the logic of your project. Use a separate erb view instead.
113
114 By default, inline rendering uses ERb. You can force it to use Builder instead with the +:type+ option:
115
116 [source, ruby]
117 -------------------------------------------------------
118 render :inline => "xml.p {'Horrid coding practice!'}", :type => :builder
119 -------------------------------------------------------
120
121 ==== Using +render+ with +:update+
122
123 You can also render javascript-based page updates inline using the +:update+ option to +render+:
124
125 [source, ruby]
126 -------------------------------------------------------
127 render :update do |page|
128 page.replace_html 'warning', "Invalid options supplied"
129 end
130 -------------------------------------------------------
131
132 WARNING: Placing javascript updates in your controller may seem to streamline small updates, but it defeats the MVC orientation of Rails and will make it harder for other developers to follow the logic of your project. I recommend using a separate rjs template instead, no matter how small the update.
133
134 ==== Rendering Text
135
136 You can send plain text - with no markup at all - back to the browser by using the +:text+ option to +render+:
137
138 [source, ruby]
139 -------------------------------------------------------
140 render :text => "OK"
141 -------------------------------------------------------
142
143 TIP: Rendering pure text is most useful when you're responding to AJAX or web service requests that are expecting something other than proper HTML.
144
145 NOTE: By default, if you use the +:text+ option, the file is rendered without using the current layout. If you want Rails to put the text into the current layout, you need to add the +:layout => true+ option
146
147 ==== Rendering JSON
148
149 JSON is a javascript data format used by many AJAX libraries. Rails has built-in support for converting objects to JSON and rendering that JSON back to the browser:
150
151 [source, ruby]
152 -------------------------------------------------------
153 render :json => @product
154 -------------------------------------------------------
155
156 TIP: You don't need to call +to_json+ on the object that you want to render. If you use the +:json+ option, +render+ will automatically call +to_json+ for you.
157
158 ==== Rendering XML
159
160 Rails also has built-in support for converting objects to XML and rendering that XML back to the caller:
161
162 [source, ruby]
163 -------------------------------------------------------
164 render :xml => @product
165 -------------------------------------------------------
166
167 TIP: You don't need to call +to_xml+ on the object that you want to render. If you use the +:xml+ option, +render+ will automatically call +to_xml+ for you.
168
169 ==== Rendering Vanilla JavaScript
170
171 Rails can render vanilla JavaScript (as an alternative to using +update+ with n +.rjs+ file):
172
173 [source, ruby]
174 -------------------------------------------------------
175 render :js => "alert('Hello Rails');"
176 -------------------------------------------------------
177
178 This will send the supplied string to the browser with a MIME type of +text/javascript+.
179
180 ==== Options for +render+
181
182 Calls to the +render+ method generally accept four options:
183
184 * +:content_type+
185 * +:layout+
186 * +:status+
187 * +:location+
188
189 ===== The +:content_type+ Option
190
191 By default, Rails will serve the results of a rendering operation with the MIME content-type of +text/html+ (or +application/json+ if you use the +:json+ option, or +application/xml+ for the +:xml+ option.). There are times when you might like to change this, and you can do so by setting the +:content_type+ option:
192
193 [source, ruby]
194 -------------------------------------------------------
195 render :file => filename, :content_type => 'application/rss'
196 -------------------------------------------------------
197
198 ===== The +:layout+ Option
199
200 With most of the options to +render+, the rendered content is displayed as part of the current layout. You'll learn more about layouts and how to use them later in this guide.
201
202 You can use the +:layout+ option to tell Rails to use a specific file as the layout for the current action:
203
204 [source, ruby]
205 -------------------------------------------------------
206 render :layout => 'special_layout'
207 -------------------------------------------------------
208
209 You can also tell Rails to render with no layout at all:
210
211 [source, ruby]
212 -------------------------------------------------------
213 render :layout => false
214 -------------------------------------------------------
215
216 ===== The +:status+ Option
217
218 Rails will automatically generate a response with the correct HTML status code (in most cases, this is +200 OK+). You can use the +:status+ option to change this:
219
220 [source, ruby]
221 -------------------------------------------------------
222 render :status => 500
223 render :status => :forbidden
224 -------------------------------------------------------
225
226 Rails understands either numeric status codes or symbols for status codes. You can find its list of status codes in +actionpack/lib/action_controller/status_codes.rb+. You can also see there how it maps symbols to status codes in that file.
227
228 ===== The +:location+ Option
229
230 You can use the +:location+ option to set the HTTP +Location+ header:
231
232 [source, ruby]
233 -------------------------------------------------------
234 render :xml => photo, :location => photo_url(photo)
235 -------------------------------------------------------
236
237 ==== Finding Layouts
238
239 To find the current layout, Rails first looks for a file in +app/views/layouts+ with the same base name as the controller. For example, rendering actions from the +PhotosController+ class will use +/app/views/layouts/photos.html.erb+. If there is no such controller-specific layout, Rails will use +/app/views/layouts/application.html.erb+. If there is no +.erb+ layout, Rails will use a +.builder+ layout if one exists. Rails also provides several ways to more precisely assign specific layouts to individual controllers and actions.
240
241 ===== Specifying Layouts on a per-Controller Basis
242
243 You can override the automatic layout conventions in your controllers by using the +layout+ declaration in the controller. For example:
244
245 [source, ruby]
246 -------------------------------------------------------
247 class ProductsController < ApplicationController
248 layout "inventory"
249 #...
250 end
251 -------------------------------------------------------
252
253 With this declaration, all methods within +ProductsController+ will use +app/views/layouts/inventory.html.erb+ for their layout.
254
255 To assign a specific layout for the entire application, use a declaration in your +ApplicationController+ class:
256
257 [source, ruby]
258 -------------------------------------------------------
259 class ApplicationController < ActionController::Base
260 layout "main"
261 #...
262 end
263 -------------------------------------------------------
264
265 With this declaration, all views in the entire application will use +app/views/layouts/main.html.erb+ for their layout.
266
267 ===== Choosing Layouts at Runtime
268
269 You can use a symbol to defer the choice of layout until a request is processed:
270
271 [source, ruby]
272 -------------------------------------------------------
273 class ProductsController < ApplicationController
274 layout :products_layout
275
276 def show
277 @product = Product.find(params[:id])
278 end
279
280 private
281 def products_layout
282 @current_user.special? ? "special" : "products"
283 end
284
285 end
286 -------------------------------------------------------
287
288 Now, if the current user is a special user, they'll get a special layout when viewing a product. You can even use an inline method to determine the layout:
289
290 [source, ruby]
291 -------------------------------------------------------
292 class ProductsController < ApplicationController
293 layout proc{ |controller| controller.
294 # ...
295 end
296 -------------------------------------------------------
297
298 ===== Conditional Layouts
299
300 Layouts specified at the controller level support +:only+ and +:except+ options that take either a method name or an array of method names:
301
302 -------------------------------------------------------
303 class ProductsController < ApplicationController
304 layout "inventory", :only => :index
305 layout "product", :except => [:index, :rss]
306 #...
307 end
308 -------------------------------------------------------
309
310 With those declarations, the +inventory+ layout would be used only for the +index+ method, the +product+ layout would be used for everything else except the +rss+ method, and the +rss+ method will have its layout determined by the automatic layout rules.
311
312 ===== Layout Inheritance
313
314 Layouts are shared downwards in the hierarchy, and more specific layouts always override more general ones. For example:
315
316 +application.rb+:
317
318 [source, ruby]
319 -------------------------------------------------------
320 class ApplicationController < ActionController::Base
321 layout "main"
322 #...
323 end
324 -------------------------------------------------------
325
326 +posts_controller.rb+:
327
328 [source, ruby]
329 -------------------------------------------------------
330 class PostsController < ApplicationController
331 # ...
332 end
333 -------------------------------------------------------
334
335 +special_posts_controller.rb+:
336
337 [source, ruby]
338 -------------------------------------------------------
339 class SpecialPostsController < PostsController
340 layout "special"
341 # ...
342 end
343 -------------------------------------------------------
344
345 +old_posts_controller.rb+:
346
347 [source, ruby]
348 -------------------------------------------------------
349 class OldPostsController < SpecialPostsController
350 layout nil
351
352 def show
353 @post = Post.find(params[:id])
354 end
355
356 def index
357 @old_posts = Post.older
358 render :layout => "old"
359 end
360 # ...
361 end
362 -------------------------------------------------------
363
364 In this application:
365
366 * In general, views will be rendered in the +main+ layout
367 * +PostsController#index+ will use the +main+ layout
368 * +SpecialPostsController#index+ will use the +special+ layout
369 * +OldPostsController#show+ will use no layout at all
370 * +OldPostsController#index+ will use the +old+ layout
371
372 ==== Avoiding Double Render Errors
373
374 Sooner or later, most Rails developers will see the error message "Can only render or redirect once per action". While this is annoying, it's relatively easy to fix. Usually it happens because of a fundamental misunderstanding of the way that +render+ works.
375
376 For example, here's some code that will trigger this error:
377
378 [source, ruby]
379 -------------------------------------------------------
380 def show
381 @book = Book.find(params[:id])
382 if @book.special?
383 render :action => "special_show"
384 end
385 end
386 -------------------------------------------------------
387
388 If +@book.special?+ evaluates to +true+, Rails will start the rendering process to dump the +@book+ variable into the +special_show+ view. But this will _not_ stop the rest of the code in the +show+ action from running, and when Rails hits the end of the action, it will start to render the +show+ view - and throw an error. The solution is simple: make sure that you only have one call to +render+ or +redirect+ in a single code path. One thing that can help is +and return+. Here's a patched version of the method:
389
390 [source, ruby]
391 -------------------------------------------------------
392 def show
393 @book = Book.find(params[:id])
394 if @book.special?
395 render :action => "special_show" and return
396 end
397 end
398 -------------------------------------------------------
399
400 === Using +redirect_to+
401
402 Another way to handle returning responses to a HTTP request is with +redirect_to+. As you've seen, +render+ tells Rails which view (or other asset) to use in constructing a response. The +redirect_to+ method does something completely different: it tells the browser to send a new request for a different URL. For example, you could redirect from wherever you are in your code to the index of photos in your application with this call:
403
404 [source, ruby]
405 -------------------------------------------------------
406 redirect_to photos_path
407 -------------------------------------------------------
408
409 You can use +redirect_to+ with any arguments that you could use with +link_to+ or +url_for+. In addition, there's a special redirect that sends the user back to the page they just came from:
410
411 -------------------------------------------------------
412 redirect_to :back
413 -------------------------------------------------------
414
415 ==== Getting a Different Redirect Status Code
416
417 Rails uses HTTP status code 302 (permanent redirect) when you call +redirect_to+. If you'd like to use a different status code (perhaps 301, temporary redirect), you can do so by using the +:status+ option:
418
419 -------------------------------------------------------
420 redirect_to photos_path, :status => 301
421 -------------------------------------------------------
422
423 Just like the +:status+ option for +render+, +:status+ for +redirect_to+ accepts both numeric and symbolic header designations.
424
425 ==== The Difference Between +render+ and +redirect+
426
427 Sometimes inexperienced developers conceive of +redirect_to+ as a sort of +goto+ command, moving execution from one place to another in your Rails code. This is _not_ correct. Your code stops running and waits for a new request for the browser. It just happens that you've told the browser what request it should make next, by sending back a HTTP 302 status code.
428
429 Consider these actions to see the difference:
430
431 [source, ruby]
432 -------------------------------------------------------
433 def index
434 @books = Book.find(:all)
435 end
436
437 def show
438 @book = Book.find(params[:id])
439 if @book.nil?
440 render :action => "index" and return
441 end
442 end
443 -------------------------------------------------------
444
445 With the code in this form, there will be likely be a problem if the +@book+ variable is +nil+. Remember, a +render :action+ doesn't run any code in the target action, so nothing will set up the +@books+ variable that the +index+ view is presumably depending on. One way to fix this is to redirect instead of rendering:
446
447 [source, ruby]
448 -------------------------------------------------------
449 def index
450 @books = Book.find(:all)
451 end
452
453 def show
454 @book = Book.find(params[:id])
455 if @book.nil?
456 redirect_to :action => "index" and return
457 end
458 end
459 -------------------------------------------------------
460
461 With this code, the browser will make a fresh request for the index page, the code in the +index+ method will run, and all will be well.
462
463 === Using +head+ To Build Header-Only Responses
464
465 The +head+ method exists to let you send back responses to the browser that have only headers. It provides a more obvious alternative to calling +render :nothing+. The +head+ method takes one response, which is interpreted as a hash of header names and values. For example, you can return only an error header:
466
467 [source, ruby]
468 -------------------------------------------------------
469 head :bad_request
470 -------------------------------------------------------
471
472 Or you can use other HTTP headers to convey additional information:
473
474 [source, ruby]
475 -------------------------------------------------------
476 head :created, :location => photo_path(@photo)
477 -------------------------------------------------------
478
479 == Structuring Layouts
480
481 When Rails renders a view as a response, it does so by combining the view with the current layout (using the rules for finding the current layout that were covered earlier in this guide). Within a layout, you have access to three tools for combining different bits of output to form the overall response:
482
483 * Asset tags
484 * +yield+ and +content_for+
485 * Partials
486
487 I'll discuss each of these in turn.
488
489 === Asset Tags
490
491 Asset tags provide methods for generating HTML that links views to assets like images, javascript, stylesheets, and feeds. There are four types of include tag:
492
493 * auto_discovery_link_tag
494 * javascript_include_tag
495 * stylesheet_link_tag
496 * image_tag
497
498 You can use these tags in layouts or other views, although the tags other than +image_tag+ are most commonly used in the +<head>+ section of a layout.
499
500 WARNING: The asset tags do _not_ verify the existence of the assets at the specified locations; they simply assume that you know what you're doing and generate the link.
501
502 ==== Linking to Feeds with +auto_discovery_link_tag+
503
504 The +auto_discovery_link_tag helper builds HTML that most browsers and newsreaders can use to detect the presences of RSS or ATOM feeds. It takes the type of the link (+:rss+ or +:atom+), a hash of options that are passed through to url_for, and a hash of options for the tag:
505
506 [source, ruby]
507 -------------------------------------------------------
508 <%= auto_discovery_link_tag(:rss, {:action => "feed"}, {:title => "RSS Feed"}) %>
509 -------------------------------------------------------
510
511 There are three tag options available for +auto_discovery_link_tag+:
512
513 * +:rel+ specifies the +rel+ value in the link (defaults to "alternate")
514 * +:type+ specifies an explicit MIME type. Rails will generate an appropriate MIME type automatically
515 * +:title+ specifies the title of the link
516
517 ==== Linking to Javascript Files with +javascript_include_tag+
518
519 The +javascript_include_tag+ helper returns an HTML +<script>+ tag for each source provided. Rails looks in +public/javascripts+ for these files by default, but you can specify a full path relative to the document root, or a URL, if you prefer. For example, to include +public/javascripts/main.js+:
520
521 [source, ruby]
522 -------------------------------------------------------
523 <%= javascript_include_tag "main" %>
524 -------------------------------------------------------
525
526 To include +public/javascripts/main.js+ and +public/javascripts/columns.js+:
527
528 [source, ruby]
529 -------------------------------------------------------
530 <%= javascript_include_tag "main", "columns" %>
531 -------------------------------------------------------
532
533 To include +public/javascripts/main.js+ and +public/photos/columns.js+:
534
535 [source, ruby]
536 -------------------------------------------------------
537 <%= javascript_include_tag "main", "/photos/columns" %>
538 -------------------------------------------------------
539
540 To include +http://example.com/main.js+:
541
542 [source, ruby]
543 -------------------------------------------------------
544 <%= javascript_include_tag "http://example.com/main.js" %>
545 -------------------------------------------------------
546
547 The +defaults+ option loads the Prototype and Scriptaculous libraries:
548
549 [source, ruby]
550 -------------------------------------------------------
551 <%= javascript_include_tag :defaults %>
552 -------------------------------------------------------
553
554 The +all+ option loads every javascript file in +public/javascripts+, starting with the Prototype and Scriptaculous libraries:
555
556 [source, ruby]
557 -------------------------------------------------------
558 <%= javascript_include_tag :all %>
559 -------------------------------------------------------
560
561 You can supply the +:recursive+ option to load files in subfolders of +public/javascripts+ as well:
562
563 [source, ruby]
564 -------------------------------------------------------
565 <%= javascript_include_tag :all, :recursive => true %>
566 -------------------------------------------------------
567
568 If you're loading multiple javascript files, you can create a better user experience by combining multiple files into a single download. To make this happen in production, specify +:cache => true+ in your +javascript_include_tag+:
569
570 [source, ruby]
571 -------------------------------------------------------
572 <%= javascript_include_tag "main", "columns", :cache => true %>
573 -------------------------------------------------------
574
575 By default, the combined file will be delivered as +javascripts/all.js+. You can specify a location for the cached asset file instead:
576
577 [source, ruby]
578 -------------------------------------------------------
579 <%= javascript_include_tag "main", "columns", :cache => 'cache/main/display' %>
580 -------------------------------------------------------
581
582 You can even use dynamic paths such as "cache/#{current_site}/main/display"+.
583
584 ==== Linking to CSS Files with +stylesheet_link_tag+
585
586 The +stylesheet_link_tag+ helper returns an HTML +<link>+ tag for each source provided. Rails looks in +public/stylesheets+ for these files by default, but you can specify a full path relative to the document root, or a URL, if you prefer. For example, to include +public/stylesheets/main.cs+:
587
588 [source, ruby]
589 -------------------------------------------------------
590 <%= stylesheet_link_tag "main" %>
591 -------------------------------------------------------
592
593 To include +public/stylesheets/main.css+ and +public/stylesheets/columns.css+:
594
595 [source, ruby]
596 -------------------------------------------------------
597 <%= stylesheet_link_tag "main", "columns" %>
598 -------------------------------------------------------
599
600 To include +public/stylesheets/main.css+ and +public/photos/columns.css+:
601
602 [source, ruby]
603 -------------------------------------------------------
604 <%= stylesheet_link_tag "main", "/photos/columns" %>
605 -------------------------------------------------------
606
607 To include +http://example.com/main.cs+:
608
609 [source, ruby]
610 -------------------------------------------------------
611 <%= stylesheet_link_tag "http://example.com/main.cs" %>
612 -------------------------------------------------------
613
614 By default, +stylesheet_link_tag+ creates links with +media="screen" rel="stylesheet" type="text/css"+. You can override any of these defaults by specifying an appropriate option (:media, :rel, or :type):
615
616 [source, ruby]
617 -------------------------------------------------------
618 <%= stylesheet_link_tag "main_print", media => "print" %>
619 -------------------------------------------------------
620
621 The +all+ option links every CSS file in +public/stylesheets+:
622
623 [source, ruby]
624 -------------------------------------------------------
625 <%= stylesheet_link_tag :all %>
626 -------------------------------------------------------
627
628 You can supply the +:recursive+ option to link files in subfolders of +public/stylesheets+ as well:
629
630 [source, ruby]
631 -------------------------------------------------------
632 <%= stylesheet_link_tag :all, :recursive => true %>
633 -------------------------------------------------------
634
635 If you're loading multiple CSS files, you can create a better user experience by combining multiple files into a single download. To make this happen in production, specify +:cache => true+ in your +stylesheet_link_tag+:
636
637 [source, ruby]
638 -------------------------------------------------------
639 <%= stylesheet_link_tag "main", "columns", :cache => true %>
640 -------------------------------------------------------
641
642 By default, the combined file will be delivered as +stylesheets/all.css+. You can specify a location for the cached asset file instead:
643
644 [source, ruby]
645 -------------------------------------------------------
646 <%= stylesheet_link_tag "main", "columns", :cache => 'cache/main/display' %>
647 -------------------------------------------------------
648
649 You can even use dynamic paths such as "cache/#{current_site}/main/display"+.
650
651 ==== Linking to Images with +image_tag+
652
653 The +image_tag+ helper builds an HTML +<image>+ tag to the specified file. By default, files are loaded from +public/images+. If you don't specify an extension, .png is assumed by default:
654
655 [source, ruby]
656 -------------------------------------------------------
657 <%= image_tag "header" %>
658 -------------------------------------------------------
659
660 You can supply a path to the image if you like:
661
662 [source, ruby]
663 -------------------------------------------------------
664 <%= image_tag "icons/delete.gif" %>
665 -------------------------------------------------------
666
667 You can supply a hash of additional HTML options:
668
669 [source, ruby]
670 -------------------------------------------------------
671 <%= image_tag "icons/delete.gif", :height => 45 %>
672 -------------------------------------------------------
673
674 There are also three special options you can use with +image_tag+:
675
676 * +:alt+ specifies the alt text for the image (which defaults to the file name of the file, capitalized and with no extension)
677 * +:size+ specifies both width and height, in the format "{width}x{height}" (for example, "150x125")
678 * +:mouseover+ sets an alternate image to be used when the onmouseover event is fired.
679
680 === Understanding +yield+
681
682 Within the context of a layout, +yield+ identifies a section where content from the view should be inserted. The simplest way to use this is to have a single +yield+, into which the entire contents of the view currently being rendered is inserted:
683
684 [source, html]
685 -------------------------------------------------------
686 <html>
687 <head>
688 </head>
689 <body>
690 <%= yield %>
691 <hbody>
692 </html>
693 -------------------------------------------------------
694
695 You can also create a layout with multiple yielding regions:
696
697 [source, html]
698 -------------------------------------------------------
699 <html>
700 <head>
701 <%= yield :head %>
702 </head>
703 <body>
704 <%= yield %>
705 <hbody>
706 </html>
707 -------------------------------------------------------
708
709 The main body of the view will always render into the unnamed +yield+. To render content into a named +yield+, you use the +content_for+ method.
710
711 === Using +content_for+
712
713 The +content_for+ method allows you to insert content into a +yield+ block in your layout. You only use +content_for+ to insert content in named yields. For example, this view would work with the layout that you just saw:
714
715 [source, html]
716 -------------------------------------------------------
717 <% content_for :head do %>
718 <title>A simple page</title>
719 <% end %>
720
721 <p>Hello, Rails!</p>
722 -------------------------------------------------------
723
724 The result of rendering this page into the supplied layout would be this HTML:
725
726 [source, html]
727 -------------------------------------------------------
728 <html>
729 <head>
730 <title>A simple page</title>
731 </head>
732 <body>
733 <p>Hello, Rails!</p>
734 <hbody>
735 </html>
736 -------------------------------------------------------
737
738 The +content_for+ method is very helpful when your layout contains distinct regions such as sidebars and footers that should get their own blocks of content inserted. It's also useful for inserting tags that load page-specific javascript or css files into the header of an otherwise-generic layout.
739
740 === Using Partials
741
742 Partial templates - usually just called "partials" - are another device for breaking apart the rendering process into more manageable chunks. With a partial, you can move the code for rendering a particular piece of a response to its own file.
743
744 ==== Naming Partials
745
746 To render a partial as part of a view, you use the +render+ method within the view, and include the +:partial+ option:
747
748 [source, ruby]
749 -------------------------------------------------------
750 <%= render :partial => "menu" %>
751 -------------------------------------------------------
752
753 This will render a file named +_menu.html.erb+ at that point within the view being rendered. Note the leading underscore character: partials are named with a leading underscore to distinguish them from regular views, even though they are referred to without the underscore. This holds true even when you're pulling in a partial from another folder:
754
755 [source, ruby]
756 -------------------------------------------------------
757 <%= render :partial => "shared/menu" %>
758 -------------------------------------------------------
759
760 That code will pull in the partial from +app/views/shared/_menu.html.erb+.
761
762 ==== Using Partials to Simplify Views
763
764 One way to use partials is to treat them as the equivalent of subroutines: as a way to move details out of a view so that you can grasp what's going on more easily. For example, you might have a view that looked like this:
765
766 [source, html]
767 -------------------------------------------------------
768 <%= render :partial => "shared/ad_banner" %>
769
770 <h1>Products</h1>
771
772 <p>Here are a few of our fine products:</p>
773 ...
774
775 <%= render :partial => "shared/footer" %>
776 -------------------------------------------------------
777
778 Here, the +_ad_banner.html.erb+ and +_footer.html.erb+ partials could contain content that is shared among many pages in your application. You don't need to see the details of these sections when you're concentrating on a particular page.
779
780 TIP: For content that is shared among all pages in your application, you can use partials directly from layouts.
781
782 ==== Partial Layouts
783
784 A partial can use its own layout file, just as a view can use a layout. For example, you might call a partial like this:
785
786 [source, html]
787 -------------------------------------------------------
788 <%= render :partial => "link_area", :layout => "graybar" %>
789 -------------------------------------------------------
790
791 This would look for a partial named +_link_area.html.erb+ and render it using the layout +_graybar.html.erb+. Note that layouts for partials follow the same leading-underscore naming as regular partials, and are placed in the same folder with the partial that they belong to (not in the master +layouts+ folder).
792
793 ==== Passing Local Variables
794
795 You can also pass local variables into partials, making them even more powerful and flexible. For example, you can use this technique to reduce duplication between new and edit pages, while still keeping a bit of distinct content:
796
797 +new.html.erb+:
798
799 [source, html]
800 -------------------------------------------------------
801 <h1>New zone</h1>
802 <%= error_messages_for :zone %>
803 <%= render :partial => "form", :locals => { :button_label => "Create zone", :zone => @zone } %>
804 -------------------------------------------------------
805
806 +edit.html.erb+:
807
808 [source, html]
809 -------------------------------------------------------
810 <h1>Editing zone</h1>
811 <%= error_messages_for :zone %>
812 <%= render :partial => "form", :locals => { :button_label => "Update zone", :zone => @zone } %>
813 -------------------------------------------------------
814
815 +_form.html.erb:+
816
817 [source, html]
818 -------------------------------------------------------
819 <% form_for(zone) do |f| %>
820 <p>
821 <b>Zone name</b><br />
822 <%= f.text_field :name %>
823 </p>
824 <p>
825 <%= f.submit button_label %>
826 </p>
827 <% end %>
828 -------------------------------------------------------
829
830 Although the same partial will be rendered into both views, the label on the submit button is controlled by a local variable passed into the partial.
831
832 Every partial also has a local variable with the same name as the partial (minus the underscore). You can pass an object in to this local variable via the +:object+ option:
833
834 [source, html]
835 -------------------------------------------------------
836 <%= render :partial => "customer", :object => @new_customer %>
837 -------------------------------------------------------
838
839 Within the +customer+ partial, the +@customer+ variable will refer to +@new_customer+ from the parent view.
840
841 WARNING: In previous versions of Rails, the default local variable would look for an instance variable with the same name as the partial in the parent. This behavior is deprecated in Rails 2.2 and will be removed in a future version.
842
843 If you have an instance of a model to render into a partial, you can use a shorthand syntax:
844
845 [source, html]
846 -------------------------------------------------------
847 <%= render :partial => @customer %>
848 -------------------------------------------------------
849
850 Assuming that the +@customer+ instance variable contains an instance of the +Customer+ model, this will use +_customer.html.erb+ to render it.
851
852 ==== Rendering Collections
853
854 Partials are very useful in rendering collections. When you pass a collection to a partial via the +:collection+ option, the partial will be inserted once for each member in the collection:
855
856 +index.html.erb+:
857
858 [source, html]
859 -------------------------------------------------------
860 <h1>Products</h1>
861 <%= render :partial => "product", :collection => @products %>
862 -------------------------------------------------------
863
864 +_product.html.erb+:
865
866 [source, html]
867 -------------------------------------------------------
868 <p>Product Name: <%= product.name %></p>
869 -------------------------------------------------------
870
871 When a partial is called with a pluralized collection, then the individual instances of the partial have access to the member of the collection being rendered via a variable named after the partial. In this case, the partial is +_product, and within the +_product+ partial, you can refer to +product+ to get the instance that is being rendered. To use a custom local variable name within the partial, specify the +:as+ option in the call to the partial:
872
873 [source, html]
874 -------------------------------------------------------
875 <%= render :partial => "product", :collection => @products, :as => :item %>
876 -------------------------------------------------------
877
878 With this change, you can access an instance of the +@products+ collection as the +item+ local variable within the partial.
879
880 TIP: Rails also makes a counter variable available within a partial called by the collection, named after the member of the collection followed by +_counter+. For example, if you're rendering +@products+, within the partial you can refer to +product_counter+ to tell you how many times the partial has been rendered.
881
882 You can also specify a second partial to be rendered between instances of the main partial by using the +:spacer_template+ option:
883
884 [source, html]
885 -------------------------------------------------------
886 <%= render :partial => "product", :collection => @products, :spacer_template => "product_ruler" %>
887 -------------------------------------------------------
888
889 Rails will render the +_product_ruler+ partial (with no data passed in to it) between each pair of +_product+ partials.
890
891 There's also a shorthand syntax available for rendering collections. For example, if +@products+ is a collection of products, you can render the collection this way:
892
893 +index.html.erb+:
894
895 [source, html]
896 -------------------------------------------------------
897 <h1>Products</h1>
898 <%= render :partial => @products %>
899 -------------------------------------------------------
900
901 +_product.html.erb+:
902
903 [source, html]
904 -------------------------------------------------------
905 <p>Product Name: <%= product.name %></p>
906 -------------------------------------------------------
907
908 Rails determines the name of the partial to use by looking at the model name in the collection. In fact, you can even create a heterogeneous collection and render it this way, and Rails will choose the proper partial for each member of the collection:
909
910 +index.html.erb+:
911
912 [source, html]
913 -------------------------------------------------------
914 <h1>Contacts</h1>
915 <%= render :partial => [customer1, employee1, customer2, employee2] %>
916 -------------------------------------------------------
917
918 +_customer.html.erb+:
919
920 [source, html]
921 -------------------------------------------------------
922 <p>Name: <%= customer.name %></p>
923 -------------------------------------------------------
924
925 +_employee.html.erb+:
926
927 [source, html]
928 -------------------------------------------------------
929 <p>Name: <%= employee.name %></p>
930 -------------------------------------------------------
931
932 In this case, Rails will use the customer or employee partials as appropriate for each member of the collection.
933
934 == Changelog ==
935
936 http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/15[Lighthouse ticket]
937
938 * November 9, 2008: Added partial collection counter by link:../authors.html#mgunderloy[Mike Gunderloy]
939 * November 1, 2008: Added +:js+ option for +render+ by link:../authors.html#mgunderloy[Mike Gunderloy]
940 * October 16, 2008: Ready for publication by link:../authors.html#mgunderloy[Mike Gunderloy]
941 * October 4, 2008: Additional info on partials (+:object+, +:as+, and +:spacer_template+) by link:../authors.html#mgunderloy[Mike Gunderloy] (not yet approved for publication)
942 * September 28, 2008: First draft by link:../authors.html#mgunderloy[Mike Gunderloy] (not yet approved for publication)
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982