diff options
Diffstat (limited to 'guides/source/layouts_and_rendering.md')
-rw-r--r-- | guides/source/layouts_and_rendering.md | 114 |
1 files changed, 61 insertions, 53 deletions
diff --git a/guides/source/layouts_and_rendering.md b/guides/source/layouts_and_rendering.md index 71cc030f6a..ad08e5a5a9 100644 --- a/guides/source/layouts_and_rendering.md +++ b/guides/source/layouts_and_rendering.md @@ -1,4 +1,4 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON https://guides.rubyonrails.org.** Layouts and Rendering in Rails ============================== @@ -71,23 +71,25 @@ If we want to display the properties of all the books in our view, we can do so <h1>Listing Books</h1> <table> - <tr> - <th>Title</th> - <th>Summary</th> - <th></th> - <th></th> - <th></th> - </tr> - -<% @books.each do |book| %> - <tr> - <td><%= book.title %></td> - <td><%= book.content %></td> - <td><%= link_to "Show", book %></td> - <td><%= link_to "Edit", edit_book_path(book) %></td> - <td><%= link_to "Remove", book, method: :delete, data: { confirm: "Are you sure?" } %></td> - </tr> -<% end %> + <thead> + <tr> + <th>Title</th> + <th>Content</th> + <th colspan="3"></th> + </tr> + </thead> + + <tbody> + <% @books.each do |book| %> + <tr> + <td><%= book.title %></td> + <td><%= book.content %></td> + <td><%= link_to "Show", book %></td> + <td><%= link_to "Edit", edit_book_path(book) %></td> + <td><%= link_to "Destroy", book, method: :delete, data: { confirm: "Are you sure?" } %></td> + </tr> + <% end %> + </tbody> </table> <br> @@ -95,7 +97,7 @@ If we want to display the properties of all the books in our view, we can do so <%= link_to "New book", new_book_path %> ``` -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. Beginning with Rails 2, the standard extensions are `.erb` for ERB (HTML with embedded Ruby), and `.builder` for Builder (XML generator). +NOTE: The actual rendering is done by nested classes of the module [`ActionView::Template::Handlers`](http://api.rubyonrails.org/classes/ActionView/Template/Handlers.html). 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. ### Using `render` @@ -149,27 +151,26 @@ render template: "products/show" #### Rendering an Arbitrary File -The `render` method can also use a view that's entirely outside of your application (perhaps you're sharing views between two Rails applications): - -```ruby -render "/u/apps/warehouse_app/current/app/views/products/show" -``` - -Rails determines that this is a file render because of the leading slash character. To be explicit, you can use the `:file` option (which was required on Rails 2.2 and earlier): +The `render` method can also use a view that's entirely outside of your application: ```ruby render file: "/u/apps/warehouse_app/current/app/views/products/show" ``` -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. +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. + +NOTE: Using the `:file` option in combination with users input can lead to security problems +since an attacker could use this action to access security sensitive files in your file system. NOTE: By default, the file is rendered using the current layout. -TIP: If you're running Rails on Microsoft Windows, you should use the `:file` option to render a file, because Windows filenames do not have the same format as Unix filenames. +TIP: If you're running Rails on Microsoft Windows, you should use the `:file` option to +render a file, because Windows filenames do not have the same format as Unix filenames. #### Wrapping it up -The above three ways of rendering (rendering another template within the controller, rendering a template within another controller and rendering an arbitrary file on the file system) are actually variants of the same action. +The above three ways of rendering (rendering another template within the controller, rendering a template within another controller, and rendering an arbitrary file on the file system) are actually variants of the same action. In fact, in the BooksController class, inside of the update action where we want to render the edit template if the book does not update successfully, all of the following render calls would all render the `edit.html.erb` template in the `views/books` directory: @@ -222,7 +223,7 @@ service requests that are expecting something other than proper HTML. NOTE: By default, if you use the `:plain` option, the text 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 and use the `.txt.erb` +layout, you need to add the `layout: true` option and use the `.text.erb` extension for the layout file. #### Rendering HTML @@ -231,14 +232,14 @@ You can send an HTML string back to the browser by using the `:html` option to `render`: ```ruby -render html: "<strong>Not Found</strong>".html_safe +render html: helpers.tag.strong('Not Found') ``` TIP: This is useful when you're rendering a small snippet of HTML code. However, you might want to consider moving it to a template file if the markup is complex. -NOTE: This option will escape HTML entities if the string is not HTML safe. +NOTE: When using `html:` option, HTML entities will be escaped if the string is not composed with `html_safe`-aware APIs. #### Rendering JSON @@ -284,7 +285,7 @@ the response. Using `:plain` or `:html` might be more appropriate most of the time. NOTE: Unless overridden, your response returned from this render option will be -`text/html`, as that is the default content type of Action Dispatch response. +`text/plain`, as that is the default content type of Action Dispatch response. #### Options for `render` @@ -380,6 +381,7 @@ Rails understands both numeric status codes and the corresponding symbols shown | | 415 | :unsupported_media_type | | | 416 | :range_not_satisfiable | | | 417 | :expectation_failed | +| | 421 | :misdirected_request | | | 422 | :unprocessable_entity | | | 423 | :locked | | | 424 | :failed_dependency | @@ -387,6 +389,7 @@ Rails understands both numeric status codes and the corresponding symbols shown | | 428 | :precondition_required | | | 429 | :too_many_requests | | | 431 | :request_header_fields_too_large | +| | 451 | :unavailable_for_legal_reasons | | **Server Error** | 500 | :internal_server_error | | | 501 | :not_implemented | | | 502 | :bad_gateway | @@ -400,7 +403,7 @@ Rails understands both numeric status codes and the corresponding symbols shown | | 511 | :network_authentication_required | NOTE: If you try to render content along with a non-content status code -(100-199, 204, 205 or 304), it will be dropped from the response. +(100-199, 204, 205, or 304), it will be dropped from the response. ##### The `:formats` Option @@ -412,6 +415,8 @@ render formats: :xml render formats: [:json, :xml] ``` +If a template with the specified format does not exist an `ActionView::MissingTemplate` error is raised. + #### Finding Layouts 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` (or `app/views/layouts/photos.builder`). If there is no such controller-specific layout, Rails will use `app/views/layouts/application.html.erb` or `app/views/layouts/application.builder`. 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. @@ -555,7 +560,7 @@ class Admin::ProductsController < AdminController end ``` -The lookup order for a `admin/products#index` action will be: +The lookup order for an `admin/products#index` action will be: * `app/views/admin/products/` * `app/views/admin/` @@ -622,12 +627,17 @@ Another way to handle returning responses to an HTTP request is with `redirect_t redirect_to photos_url ``` -You can use `redirect_to` with any arguments that you could use with `link_to` or `url_for`. There's also a special redirect that sends the user back to the page they just came from: +You can use `redirect_back` to return the user to the page they just came from. +This location is pulled from the `HTTP_REFERER` header which is not guaranteed +to be set by the browser, so you must provide the `fallback_location` +to use in this case. ```ruby -redirect_to :back +redirect_back(fallback_location: root_path) ``` +NOTE: `redirect_to` and `redirect_back` do not halt and return immediately from method execution, but simply set HTTP responses. Statements occurring after them in a method will be executed. You can halt by an explicit `return` or some other halting mechanism, if needed. + #### Getting a Different Redirect Status Code Rails uses HTTP status code 302, a temporary redirect, when you call `redirect_to`. If you'd like to use a different status code, perhaps 301, a permanent redirect, you can use the `:status` option: @@ -697,7 +707,7 @@ This would detect that there are no books with the specified ID, populate the `@ ### Using `head` To Build Header-Only Responses -The `head` method can be used to send responses with only headers to the browser. It provides a more obvious alternative to calling `render :nothing`. The `head` method accepts a number or symbol (see [reference table](#the-status-option)) representing a HTTP status code. The options argument is interpreted as a hash of header names and values. For example, you can return only an error header: +The `head` method can be used to send responses with only headers to the browser. The `head` method accepts a number or symbol (see [reference table](#the-status-option)) representing an HTTP status code. The options argument is interpreted as a hash of header names and values. For example, you can return only an error header: ```ruby head :bad_request @@ -747,7 +757,7 @@ When Rails renders a view as a response, it does so by combining the view with t ### Asset Tag Helpers -Asset tag helpers provide methods for generating HTML that link views to feeds, JavaScript, stylesheets, images, videos and audios. There are six asset tag helpers available in Rails: +Asset tag helpers provide methods for generating HTML that link views to feeds, JavaScript, stylesheets, images, videos, and audios. There are six asset tag helpers available in Rails: * `auto_discovery_link_tag` * `javascript_include_tag` @@ -762,7 +772,7 @@ WARNING: The asset tag helpers do _not_ verify the existence of the assets at th #### Linking to Feeds with the `auto_discovery_link_tag` -The `auto_discovery_link_tag` helper builds HTML that most browsers and feed readers can use to detect the presence 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: +The `auto_discovery_link_tag` helper builds HTML that most browsers and feed readers can use to detect the presence of RSS, Atom, or JSON feeds. It takes the type of the link (`:rss`, `:atom`, or `:json`), a hash of options that are passed through to url_for, and a hash of options for the tag: ```erb <%= auto_discovery_link_tag(:rss, {action: "feed"}, @@ -1078,7 +1088,7 @@ definitions for several similar resources: * `shared/_search_filters.html.erb` ```html+erb - <%= form_for(@q) do |f| %> + <%= form_for(search) do |f| %> <h1>Search form:</h1> <fieldset> <%= yield f %> @@ -1151,23 +1161,21 @@ To pass a local variable to a partial in only specific cases use the `local_assi <%= render article, full: true %> ``` -* `_articles.html.erb` +* `_article.html.erb` ```erb - <%= content_tag_for :article, article do |article| %> - <h2><%= article.title %></h2> + <h2><%= article.title %></h2> - <% if local_assigns[:full] %> - <%= simple_format article.body %> - <% else %> - <%= truncate article.body %> - <% end %> + <% if local_assigns[:full] %> + <%= simple_format article.body %> + <% else %> + <%= truncate article.body %> <% end %> ``` This way it is possible to use the partial without the need to declare all local variables. -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: +Every partial also has a local variable with the same name as the partial (minus the leading underscore). You can pass an object in to this local variable via the `:object` option: ```erb <%= render partial: "customer", object: @new_customer %> @@ -1202,7 +1210,7 @@ Partials are very useful in rendering collections. When you pass a collection to 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. -There is also a shorthand for this. Assuming `@products` is a collection of `product` instances, you can simply write this in the `index.html.erb` to produce the same result: +There is also a shorthand for this. Assuming `@products` is a collection of `Product` instances, you can simply write this in the `index.html.erb` to produce the same result: ```html+erb <h1>Products</h1> @@ -1258,7 +1266,7 @@ You can also pass in arbitrary local variables to any partial you are rendering In this case, the partial will have access to a local variable `title` with the value "Products Page". -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. This does not work in conjunction with the `as: :value` option. +TIP: Rails also makes a counter variable available within a partial called by the collection, named after the title of the partial followed by `_counter`. For example, when rendering a collection `@products` the partial `_product.html.erb` can access the variable `product_counter` which indexes the number of times it has been rendered within the enclosing view. Note that it also applies for when the partial name was changed by using the `as:` option. For example, the counter variable for the code above would be `item_counter`. You can also specify a second partial to be rendered between instances of the main partial by using the `:spacer_template` option: @@ -1278,7 +1286,7 @@ When rendering collections it is also possible to use the `:layout` option: <%= render partial: "product", collection: @products, layout: "special_layout" %> ``` -The layout will be rendered together with the partial for each item in the collection. The current object and object_counter variables will be available in the layout as well, the same way they do within the partial. +The layout will be rendered together with the partial for each item in the collection. The current object and object_counter variables will be available in the layout as well, the same way they are within the partial. ### Using Nested Layouts |