diff options
Diffstat (limited to 'railties/guides/source/action_view_overview.textile')
-rw-r--r-- | railties/guides/source/action_view_overview.textile | 417 |
1 files changed, 233 insertions, 184 deletions
diff --git a/railties/guides/source/action_view_overview.textile b/railties/guides/source/action_view_overview.textile index d0b3ee6bfc..2b2c197f46 100644 --- a/railties/guides/source/action_view_overview.textile +++ b/railties/guides/source/action_view_overview.textile @@ -20,7 +20,28 @@ Note: Some features of Action View are tied to Active Record, but that doesn't m h3. Using Action View with Rails -TODO... +For each controller there is an associated directory in the <tt>app/views</tt> directory which holds the template files that make up the views associated with that controller. These files are used to display the view that results from each controller action. + +Let's take a look at what Rails does by default when creating a new resource using the scaffold generator: + +<shell> +$ rails generate scaffold post + [...] + invoke scaffold_controller + create app/controllers/posts_controller.rb + invoke erb + create app/views/posts + create app/views/posts/index.html.erb + create app/views/posts/edit.html.erb + create app/views/posts/show.html.erb + create app/views/posts/new.html.erb + create app/views/posts/_form.html.erb + [...] +</shell> + +There is a naming convention for views in Rails. Typically, the views share their name with the associated controller action, as you can see above. +For example, the index controller action of the <tt>posts_controller.rb</tt> will use the <tt>index.html.erb</tt> view file in the <tt>app/views/posts</tt> directory. +The complete HTML returned to the client is composed of a combination of this ERB file, a layout template that wraps it, and all the partials that the view may reference. Later on this guide you can find a more detailed documentation of each one of this three components. h3. Using Action View outside of Rails @@ -94,9 +115,213 @@ TODO needs a screenshot? I have one - not sure where to put it. h3. Templates, Partials and Layouts -TODO... +As mentioned before, the final HTML output is a composition of three Rails elements: +Templates+, +Partials+ and +Layouts+. +Find below a brief overview of each one of them. + +h4. Templates + +Action View templates can be written in several ways. If the template file has a <tt>.erb</tt> extension then it uses a mixture of ERB (included in Ruby) and HTML. If the template file has a <tt>.builder</tt> extension then a fresh instance of <tt>Builder::XmlMarkup</tt> library is used. + +Rails supports multiple template systems and uses a file extension to distinguish amongst them. For example, an HTML file using the ERB template system will have <tt>.html.erb</tt> as a file extension. + +h5. ERB + +Within an ERB template Ruby code can be included using both +<% %>+ and +<%= %>+ tags. The +<% %>+ are used to execute Ruby code that does not return anything, such as conditions, loops or blocks, and the +<%= %>+ tags are used when you want output. + +Consider the following loop for names: + +<erb> +<b>Names of all the people</b> +<% @people.each do |person| %> + Name: <%= person.name %><br/> +<% end %> +</erb> + +The loop is setup in regular embedding tags +<% %>+ and the name is written using the output embedding tag +<%= %>+. Note that this is not just a usage suggestion, for Regular output functions like print or puts won't work with ERB templates. So this would be wrong: + +<erb> +<%# WRONG %> +Hi, Mr. <% puts "Frodo" %> +</erb> + +To suppress leading and trailing whitespaces, you can use +<%-+ +-%>+ interchangeably with +<%+ and +%>+. + +h5. Builder + +Builder templates are a more programmatic alternative to ERB. They are especially useful for generating XML content. An XmlMarkup object named +xml+ is automatically made available to templates with a <tt>.builder</tt> extension. + +Here are some basic examples: + +<ruby> +xml.em("emphasized") +xml.em { xml.b("emph & bold") } +xml.a("A Link", "href"=>"http://rubyonrails.org") +xml.target("name"=>"compile", "option"=>"fast") +</ruby> + +will produce -TODO see http://guides.rubyonrails.org/layouts_and_rendering.html +<html> +<em>emphasized</em> +<em><b>emph & bold</b></em> +<a href="http://rubyonrails.org">A link</a> +<target option="fast" name="compile" \> +</html> + +Any method with a block will be treated as an XML markup tag with nested markup in the block. For example, the following: + +<ruby> +xml.div { + xml.h1(@person.name) + xml.p(@person.bio) +} +</ruby> + +would produce something like: + +<html> +<div> + <h1>David Heinemeier Hansson</h1> + <p>A product of Danish Design during the Winter of '79...</p> +</div> +</html> + +A full-length RSS example actually used on Basecamp: + +<ruby> +xml.rss("version" => "2.0", "xmlns:dc" => "http://purl.org/dc/elements/1.1/") do + xml.channel do + xml.title(@feed_title) + xml.link(@url) + xml.description "Basecamp: Recent items" + xml.language "en-us" + xml.ttl "40" + + for item in @recent_items + xml.item do + xml.title(item_title(item)) + xml.description(item_description(item)) if item_description(item) + xml.pubDate(item_pubDate(item)) + xml.guid(@person.firm.account.url + @recent_items.url(item)) + xml.link(@person.firm.account.url + @recent_items.url(item)) + xml.tag!("dc:creator", item.author_name) if item_has_creator?(item) + end + end + end +end +</ruby> + +h5. Template caching + +By default, Rails will compile each template to a method in order to render it. When you alter a template, Rails will check the file's modification time and recompile it in development mode. + +h4. Partials + +Partial templates – usually just called "partials" – are another device for breaking 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. + +h5. Naming Partials + +To render a partial as part of a view, you use the +render+ method within the view: + +<ruby> +<%= render "menu" %> +</ruby> + +This will render a file named +_menu.html.erb+ at that point within the view is 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: + +<ruby> +<%= render "shared/menu" %> +</ruby> + +That code will pull in the partial from +app/views/shared/_menu.html.erb+. + +h5. Using Partials to Simplify Views + +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: + +<erb> +<%= render "shared/ad_banner" %> + +<h1>Products</h1> + +<p>Here are a few of our fine products:</p> +<% @products.each do |product| %> + <%= render :partial => "product", :locals => { :product => product } %> +<% end %> + +<%= render "shared/footer" %> +</erb> + +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. + +h5. The :as and :object options + +By default <tt>ActionView::Partials::PartialRenderer</tt> has its object in a local variable with the same name as the template. So, given + +<erb> +<%= render :partial => "product" %> +</erb> + +within product we'll get <tt>@product</tt> in the local variable +product+, as if we had written: + +<erb> +<%= render :partial => "product", :locals => { :product => @product } %> +</erb> + +With the <tt>:as</tt> option we can specify a different name for said local variable. For example, if we wanted it to be +item+ instead of product+ we'd do: + +<erb> +<%= render :partial => "product", :as => 'item' %> +</erb> + +The <tt>:object</tt> option can be used to directly specify which object is rendered into the partial; useful when the template's object is elsewhere, in a different ivar or in a local variable for instance. + +For example, instead of: + +<erb> +<%= render :partial => "product", :locals => { :product => @item } %> +</erb> + +you'd do: + +<erb> +<%= render :partial => "product", :object => @item %> +</erb> + +The <tt>:object</tt> and <tt>:as</tt> options can be used together. + +h5. Rendering Collections + +The example of partial use describes a familiar pattern where a template needs to iterate over an array and render a sub template for each of the elements. This pattern has been implemented as a single method that accepts an array and renders a partial by the same name as the elements contained within. +So the three-lined example for rendering all the products can be rewritten with a single line: + +<erb> +<%= render :partial => "product", :collection => @products %> +</erb> + +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. + +You can use a shorthand syntax for rendering collections. Assuming @products is a collection of +Product+ instances, you can simply write the following to produce the same result: + +<erb> +<%= render @products %> +</erb> + +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. + +h5. Spacer Templates + +You can also specify a second partial to be rendered between instances of the main partial by using the +:spacer_template+ option: + +<erb> +<%= render @products, :spacer_template => "product_ruler" %> +</erb> + +Rails will render the +_product_ruler+ partial (with no data passed in to it) between each pair of +_product+ partials. + +h4. Layouts + +TODO... h3. Using Templates, Partials and Layouts in "The Rails Way" @@ -262,9 +487,9 @@ Register one or more stylesheet files to be included when symbol is passed to +s ActionView::Helpers::AssetTagHelper.register_stylesheet_expansion :monkey => ["head", "body", "tail"] stylesheet_link_tag :monkey # => - <link href="/stylesheets/head.css" media="screen" rel="stylesheet" type="text/css" /> - <link href="/stylesheets/body.css" media="screen" rel="stylesheet" type="text/css" /> - <link href="/stylesheets/tail.css" media="screen" rel="stylesheet" type="text/css" /> + <link href="/stylesheets/head.css" media="screen" rel="stylesheet" type="text/css" /> + <link href="/stylesheets/body.css" media="screen" rel="stylesheet" type="text/css" /> + <link href="/stylesheets/tail.css" media="screen" rel="stylesheet" type="text/css" /> </ruby> h5. auto_discovery_link_tag @@ -301,7 +526,7 @@ javascript_include_tag "common" # => <script type="text/javascript" src="/javascripts/common.js"></script> </ruby> -To include the Prototype and Scriptaculous JavaScript libraries in your application, pass +:defaults+ as the source. When using +:defaults+, if an +application.js+ file exists in your +public/javascripts+ directory, it will be included as well. +If the application does not use the asset pipeline, to include the jQuery JavaScript library in your application, pass +:defaults+ as the source. When using +:defaults+, if an +application.js+ file exists in your +public/javascripts+ directory, it will be included as well. <ruby> javascript_include_tag :defaults @@ -1076,8 +1301,6 @@ h4. JavaScriptHelper Provides functionality for working with JavaScript in your views. -Rails includes the Prototype JavaScript framework and the Scriptaculous JavaScript controls and visual effects library. If you wish to use these libraries and their helpers, make sure +<%= javascript_include_tag :defaults, :cache => true %>+ is in the HEAD section of your page. This function will include the necessary JavaScript files Rails generated in the +public/javascripts+ directory. - h5. button_to_function Returns a button that'll trigger a JavaScript function using the onclick handler. Examples: @@ -1177,16 +1400,6 @@ number_with_precision(111.2345) # => 111.235 number_with_precision(111.2345, 2) # => 111.23 </ruby> -h4. PrototypeHelper - -Prototype is a JavaScript library that provides DOM manipulation, Ajax functionality, and more traditional object-oriented facilities for JavaScript. This module provides a set of helpers to make it more convenient to call functions from Prototype using Rails, including functionality to call remote Rails methods (that is, making a background request to a Rails action) using Ajax. - -To be able to use these helpers, you must first include the Prototype JavaScript framework in the HEAD of the pages with Prototype functions. - -<ruby> -javascript_include_tag 'prototype' -</ruby> - h5. evaluate_remote_response Returns +eval(request.responseText)+ which is the JavaScript function that form_remote_tag can call in +:complete+ to evaluate a multiple update return document using +update_element_function+ calls. @@ -1283,171 +1496,6 @@ would generate: return false;" type="button" value="Create" /> </html> -h5. update_page - -Yields a JavaScriptGenerator and returns the generated JavaScript code. Use this to update multiple elements on a page in an Ajax response. - -<ruby> -update_page do |page| - page.hide 'spinner' -end -</ruby> - -h5. update_page_tag - -Works like update_page but wraps the generated JavaScript in a +script+ tag. Use this to include generated JavaScript in an ERB template. - -h4. PrototypeHelper::JavaScriptGenerator::GeneratorMethods - -JavaScriptGenerator generates blocks of JavaScript code that allow you to change the content and presentation of multiple DOM elements. Use this in your Ajax response bodies, either in a +script+ tag or as plain JavaScript sent with a Content-type of "text/javascript". - -h5(#push). << - -Writes raw JavaScript to the page. - -<ruby> -page << "alert('JavaScript with Prototype.');" -</ruby> - -h5(#at). [] - -Returns a element reference by finding it through it's id in the DOM. - -<ruby> -page['blank_slate'].show # => $('blank_slate').show(); -</ruby> - -h5. alert - -Displays an alert dialog with the given message. - -<ruby> -page.alert('This message is from Rails!') -</ruby> - -h5. assign - -Assigns the JavaScript variable the given value. - -<ruby> -page.assign 'tabulated_total', @total_from_cart -</ruby> - -h5. call - -Calls the JavaScript function, optionally with the given arguments. - -<ruby> -page.call 'Element.replace', 'my_element', "My content to replace with." -</ruby> - -h5. delay - -Executes the content of the block after a delay of the number of seconds provided. - -<ruby> -page.delay(20) do - page.visual_effect :fade, 'notice' -end -</ruby> - -h5. draggable - -Creates a script.aculo.us draggable element. See ActionView::Helpers::ScriptaculousHelper for more information. - -h5. drop_receiving - -Creates a script.aculo.us drop receiving element. See ActionView::Helpers::ScriptaculousHelper for more information. - -h5. hide - -Hides the visible DOM elements with the given ids. - -<ruby> -page.hide 'person_29', 'person_9', 'person_0' -</ruby> - -h5. insert_html - -Inserts HTML at the specified position relative to the DOM element identified by the given id. - -<ruby> -page.insert_html :bottom, 'my_list', '<li>Last item</li>' -</ruby> - -h5. literal - -Returns an object whose to_json evaluates to the code provided. Use this to pass a literal JavaScript expression as an argument to another JavaScriptGenerator method. - -h5. redirect_to - -Redirects the browser to the given location using JavaScript, in the same form as +url_for+. - -<ruby> -page.redirect_to(:controller => 'accounts', :action => 'new') -</ruby> - -h5. remove - -Removes the DOM elements with the given ids from the page. - -<ruby> -page.remove 'person_23', 'person_9', 'person_2' -</ruby> - -h5. replace - -Replaces the "outer HTML" (i.e., the entire element, not just its contents) of the DOM element with the given id. - -<ruby> -page.replace 'person-45', :partial => 'person', :object => @person -</ruby> - -h5. replace_html - -Replaces the inner HTML of the DOM element with the given id. - -<ruby> -page.replace_html 'person-45', :partial => 'person', :object => @person -</ruby> - -h5(#prototype-select). select - -Returns a collection reference by finding it through a CSS pattern in the DOM. - -<ruby> -page.select('p.welcome b').first.hide # => $$('p.welcome b').first().hide(); -</ruby> - -h5. show - -Shows hidden DOM elements with the given ids. - -<ruby> -page.show 'person_6', 'person_13', 'person_223' -</ruby> - -h5. sortable - -Creates a script.aculo.us sortable element. Useful to recreate sortable elements after items get added or deleted. See ActionView::Helpers::ScriptaculousHelper for more information. - -h5. toggle - -Toggles the visibility of the DOM elements with the given ids. Example: - -<ruby> -page.toggle 'person_14', 'person_12', 'person_23' # Hides the elements -page.toggle 'person_14', 'person_12', 'person_23' # Shows the previously hidden elements -</ruby> - -h5. visual_effect - -Starts a script.aculo.us visual effect. See ActionView::Helpers::ScriptaculousHelper for more information. - - -TODO start from RecordIdentificationHelper - - h3. Localized Views Action View has the ability render different templates depending on the current locale. @@ -1472,5 +1520,6 @@ You can read more about the Rails Internationalization (I18n) API "here":i18n.ht h3. Changelog +* April 16, 2011: Added 'Using Action View with Rails', 'Templates' and 'Partials' sections. "Sebastian Martinez":http://wyeworks.com * September 3, 2009: Continuing work by Trevor Turk, leveraging the Action Pack docs and "What's new in Edge Rails":http://ryandaigle.com/articles/2007/8/3/what-s-new-in-edge-rails-partials-get-layouts * April 5, 2009: Starting work by Trevor Turk, leveraging Mike Gunderloy's docs |