Movatterモバイル変換


[0]ホーム

URL:


Skip to main content
More atrubyonrails.org:

Action View Overview

After reading this guide, you will know:

  • What Action View is and how to use it with Rails.
  • How best to use templates, partials, and layouts.
  • How to use localized views.

1. What is Action View?

Action View is the V inMVC.Action Controller and Action View worktogether to handle web requests. Action Controller is concerned withcommunicating with the model layer (of MVC) and retrieving data. Action View isthen responsible for rendering a response body to the web request using thatdata.

By default, Action View templates (also referred to simply as "views") arewritten using Embedded Ruby (ERB), which allows using Ruby code within HTMLdocuments.

Action View provides manyhelper methods for dynamically generatingHTML tags for forms, dates, and strings. It's also possible to add customhelpers to your application as needed.

Action View can make use of Active Model features liketo_paramandto_partial_pathto simplify code. That doesn't mean Action View depends on Active Model. ActionView is an independent package that can be used with any Ruby library.

2. Using Action View with Rails

Action View templates (aka "views") are stored in subdirectories in theapp/views directory. There is a subdirectory matching the name of eachcontroller. The view files inside that subdirectory are used to render specificviews as a response to controller actions.

For example, when you use scaffolding to generate anarticle resource, Railsgenerates the following files inapp/views/articles:

$bin/railsgenerate scaffold article      [...]      invoke  scaffold_controller      create    app/controllers/articles_controller.rb      invoke    erb      create      app/views/articles      create      app/views/articles/index.html.erb      create      app/views/articles/edit.html.erb      create      app/views/articles/show.html.erb      create      app/views/articles/new.html.erb      create      app/views/articles/_form.html.erb      [...]

The file names follow a Rails naming convention. They share their name with theassociated controller action. For example theindex.html.erb,edit.html.erb,etc.

By following this naming convention, Rails will automatically find and renderthe matching view at the end of a controller action, without you having tospecify it. For example, theindex action in thearticles_controller.rb willautomatically render theindex.html.erb view inside theapp/views/articles/directory. The name and the location of the file are both important.

The final HTML returned to the client is composed of a combination of the.html.erb ERB file, a layout template that wraps it, and all the partials thatthe ERB file may reference. In the rest of this guide, you will find moredetails about each of the three components:Templates,Partials,Layouts.

3. Templates

Action View templates can be written in different formats. If the template filehas a.erb extension, it uses embedded Ruby to build an HTML response. If thetemplate has a.jbuilder extension, it uses theJbuilder gem to build a JSON response. Anda template with a.builder extension uses theBuilder::XmlMarkup library to build an XMLresponse.

Rails uses the file extension to distinguish among multiple template systems.For example, an HTML file using the ERB template system will have.html.erb asa file extension, and a JSON file using the Jbuilder template system will havethe.json.jbuilder file extension. Other libraries may add other templatetypes and file extensions as well.

3.1. ERB

An ERB template is a way to sprinkle Ruby code within static HTML using specialERB tags like<% %> and<%= %>.

When Rails processes the ERB view templates ending with.html.erb, itevaluates the embedded Ruby code and replaces the ERB tags with the dynamicoutput. That dynamic content is combined with the static HTML markup to form thefinal HTML response.

Within an ERB template, Ruby code can be included using both<% %> and<%=%> tags. The<% %> tag (without the=) is used when you want to executeRuby code but not directly output the result, such as conditions or loops. Thetag<%= %> is used for Ruby code that generates an output and you want thatoutput rendered within the template, such as a model attribute likeperson.name in this example:

<h1>Names</h1><%@people.eachdo|person|%>  Name:<%=person.name%><br><%end%>

The loop is set up using regular embedding tags (<% %>) and the name isinserted using the output embedding tags (<%= %>).

Note that functions such asprint andputs won't be rendered to the viewwith ERB templates. So something like this would not work:

<%# WRONG %>Hi, Mr.<%puts"Frodo"%>

The above example shows that comments can be added in ERB within<%# %> tag.

To suppress leading and trailing whitespaces, you can use<%--%>interchangeably with<% and%>.

3.2. Jbuilder

Jbuilder is a gem that's maintained by the Rails team and included in thedefault RailsGemfile. It is used to build JSON responses using templates.

If you don't have it, you can add the following to yourGemfile:

gem"jbuilder"

AJbuilder object namedjson is automatically made available to templateswith a.jbuilder extension.

Here is a basic example:

json.name("Alex")json.email("alex@example.com")

would produce:

{"name":"Alex","email":"alex@example.com"}

See theJbuilder documentation formore examples.

3.3. Builder

Builder templates are a more programmatic alternative to ERB. It's similar toJBuilder but is used to generate XML, instead of JSON.

AnXmlMarkup object namedxml is automatically made available to templateswith a.builder extension.

Here is a basic examples:

xml.em("emphasized")xml.em{xml.b("emph & bold")}xml.a("A Link","href"=>"https://rubyonrails.org")xml.target("name"=>"compile","option"=>"fast")

which would produce:

<em>emphasized</em><em><b>emph&amp; bold</b></em><ahref="https://rubyonrails.org">A link</a><targetoption="fast"name="compile"/>

Any method with a block will be treated as an XML markup tag with nested markupin the block. For example, the following:

xml.div{xml.h1(@person.name)xml.p(@person.bio)}

would produce something like:

<div><h1>David Heinemeier Hansson</h1><p>A product of Danish Design during the Winter of '79...</p></div>

SeeBuilder documentation for more examples.

3.4. Template Compilation

By default, Rails will compile each template to a method to render it. In thedevelopment environment, when you alter a template, Rails will check the file'smodification time and recompile it.

There is also Fragment Caching for when different parts of the page need to becached and expired separately. Learn more about it in thecachingguide.

4. Partials

Partial templates - usually just called "partials" - are a way of breaking upthe view templates into smaller reusable chunks. With partials, you can extracta piece of code from your main template to a separate smaller file, and renderthat file in the main template. You can also pass data to the partial files fromthe main template.

Let's see this in action with some examples:

4.1. Rendering Partials

To render a partial as part of a view, you use therendermethod within the view:

<%=render"product"%>

This will look for a file named_product.html.erb in the same folder to renderwithin that view. Partial file names start with leading underscore character byconvention. The file name distinguishes partials from regular views. However, nounderscore is used when referring to partials for rendering within a view. Thisis true even when you reference a partial from another directory:

<%=render"application/product"%>

That code will look for and display a partial file named_product.html.erb inapp/views/application/.

4.2. Using Partials to Simplify Views

One way to use partials is to treat them as the equivalent of methods. A way tomove details out of a view so that you can grasp what's going on more easily.For example, you might have a view that looks like this:

<%=render"application/ad_banner"%><h1>Products</h1><p>Here are a few of our fine products:</p><%@products.eachdo|product|%><%=renderpartial:"product",locals:{product:product}%><%end%><%=render"application/footer"%>

Here, the_ad_banner.html.erb and_footer.html.erb partials could containcontent that is shared among many pages in your application. You don't need tosee the details of these sections when you're focused on a Products' page.

The above example also uses the_product.html.erb partial. This partialcontains details for rendering an individual product and is used to render eachproduct in the collection@products.

4.3. Passing Data to Partials withlocals Option

When rendering a partial, you can pass data to the partial from the renderingview. You use thelocals: options hash for this. Each key in thelocals:option is available as a partial-local variable:

<%# app/views/products/show.html.erb %><%=renderpartial:"product",locals:{my_product:@product}%><%# app/views/products/_product.html.erb %><%=tag.divid:dom_id(my_product)do%><h1><%=my_product.name%></h1><%end%>

A "partial-local variable" is a variable that is local to a given partial andonly available from within that partial. In the above example,my_product is apartial-local variable. It was assigned the value of@product when passed tothe partial from the original view.

Note that typically we'd simply call this local variableproduct. We are usingmy_product to distinguish it from the instance variable name and template namein this example.

Sincelocals is a hash, you can pass in multiple variables as needed, likelocals: { my_product: @product, my_reviews: @reviews }.

However, if a template refers to a variable thatisn't passed into the view aspart of thelocals: option, the template will raise anActionView::Template::Error:

<%# app/views/products/_product.html.erb %><%=tag.divid:dom_id(my_product)do%><h1><%=my_product.name%></h1><%# => raises ActionView::Template::Error for `product_reviews` %><%product_reviews.eachdo|review|%><%# ... %><%end%><%end%>

4.4. Usinglocal_assigns

Each partial has a method calledlocal_assigns available. You can use thismethod to access keys passed via thelocals: option. If a partial was notrendered with:some_key set, the value oflocal_assigns[:some_key] will benil within the partial.

For example,product_reviews isnil in the below example since onlyproduct is set inlocals::

<%# app/views/products/show.html.erb %><%=renderpartial:"product",locals:{product:@product}%><%# app/views/products/_product.html.erb %><%local_assigns[:product]# => "#<Product:0x0000000109ec5d10>"%><%local_assigns[:product_reviews]# => nil%>

One use case forlocal_assigns is optionally passing in a local variable andthen conditionally performing an action in the partial based on whether thelocal variable is set. For example:

<%iflocal_assigns[:redirect]%><%=form.hidden_field:redirect,value:true%><%end%>

Another example from Active Storage's_blob.html.erb. This one sets the sizebased on whetherin_gallery local variable is set when rendering the partialthat contains this line:

<%=image_tagblob.representation(resize_to_limit:local_assigns[:in_gallery]?[800,600]:[1024,768])%>

4.5.render withoutpartial andlocals Options

In the above examples,render takes 2 options:partial andlocals. But ifthese are the only options you need to use, you can skip the keys,partial andlocals, and specify the values only.

For example, instead of:

<%=renderpartial:"product",locals:{product:@product}%>

You can write:

<%=render"product",product:@product%>

You can also use this shorthand based on conventions:

<%=render@product%>

This will look for a partial named_product.html.erb inapp/views/products/,as well as pass a local namedproduct set to the value@product.

4.6. Theas andobject Options

By default, objects passed to the template are in a local variable with the samename as the template. So, given:

<%=render@product%>

within the_product.html.erb partial you'll get@product instance variablein the local variableproduct, as if you had written:

<%=renderpartial:"product",locals:{product:@product}%>

Theobject option can be used to specify a different name. This is useful whenthe template's object is elsewhere (e.g. in a different instance variable or ina local variable).

For example, instead of:

<%=renderpartial:"product",locals:{product:@item}%>

you can write:

<%=renderpartial:"product",object:@item%>

This assigns the instance variable@item to a partial local variable namedproduct. What if you wanted to change the local variable name from the defaultproduct to something else? You can use the:as option for that.

With theas option, you can specify a different name for the local variablelike this:

<%=renderpartial:"product",object:@item,as:"item"%>

This is equivalent to

<%=renderpartial:"product",locals:{item:@item}%>

4.7. Rendering Collections

It's common for a view to iterate over a collection, such as@products, andrender a partial template for each object in the collection. This pattern hasbeen implemented as a single method that accepts an array and renders a partialfor each one of the elements in the array.

So this example for rendering all the products:

<%@products.eachdo|product|%><%=renderpartial:"product",locals:{product:product}%><%end%>

can be rewritten in a single line:

<%=renderpartial:"product",collection:@products%>

When a partial is called with a collection, the individual instances of thepartial have access to the member of the collection being rendered via avariable named after the partial. In this case, since the partial is_product.html.erb, you can useproduct to refer to the collection memberthat is being rendered.

You can also use the following conventions based shorthand syntax for renderingcollections.

<%=render@products%>

The above assumes that@products is a collection ofProduct instances. Railsuses naming conventions to determine the name of the partial to use by lookingat the model name in the collection,Product in this case. In fact, you caneven render a collection made up of instances of different models using thisshorthand, and Rails will choose the proper partial for each member of thecollection.

4.8. Spacer Templates

You can also specify a second partial to be rendered between instances of themain partial by using the:spacer_template option:

<%=renderpartial:@products,spacer_template:"product_ruler"%>

Rails will render the_product_ruler.html.erb partial (with no data passed toit) between each pair of_product.html.erb partials.

4.9. Counter Variables

Rails also makes a counter variable available within a partial called by thecollection. The variable is 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 variableproduct_counter. The variableindexes the number of times the partial has been rendered within the enclosingview, starting with a value of0 on the first render.

<%# index.html.erb %><%=renderpartial:"product",collection:@products%>
<%# _product.html.erb %><%=product_counter%> # 0 for the first product, 1 for the second product...

This also works when the local variable name is changed using theas: option.So if you didas: :item, the counter variable would beitem_counter.

When rendering collections with instances of different models, the counter variable increments for each partial, regardless of the class of the model being rendered.

Note: The following two sections,Strict Locals andLocalAssigns with Pattern Matching are moreadvanced features of using partials, included here for completeness.

4.10.local_assigns with Pattern Matching

Sincelocal_assigns is aHash, it's compatible withRuby 3.1's patternmatching assignmentoperator:

local_assigns=>{product:,**options}product# => "#<Product:0x0000000109ec5d10>"options# => {}

When keys other than:product are assigned into a partial-localHashvariable, they can be splatted into helper method calls:

<%# app/views/products/_product.html.erb %><%local_assigns=>{product:,**options}%><%=tag.divid:dom_id(product),**optionsdo%><h1><%=product.name%></h1><%end%><%# app/views/products/show.html.erb %><%=render"products/product",product:@product,class:"card"%><%# => <div>  #      <h1>A widget</h1>  #    </div>%>

Pattern matching assignment also supports variable renaming:

local_assigns=>{product:record}product# => "#<Product:0x0000000109ec5d10>"record# => "#<Product:0x0000000109ec5d10>"product==record# => true

You can also conditionally read a variable, then fall back to a default valuewhen the key isn't part of thelocals: options, usingfetch:

<%# app/views/products/_product.html.erb %><%local_assigns.fetch(:related_products,[]).eachdo|related_product|%><%# ... %><%end%>

Combining Ruby 3.1's pattern matching assignment with calls toHash#with_defaultsenables compact partial-local default variable assignments:

<%# app/views/products/_product.html.erb %><%local_assigns.with_defaults(related_products:[])=>{product:,related_products:}%><%=tag.divid:dom_id(product)do%><h1><%=product.name%></h1><%related_products.eachdo|related_product|%><%# ... %><%end%><%end%>

4.11. Strict Locals

Action View partials are compiled into regular Ruby methods under the hood.Because it is impossible in Ruby to dynamically create local variables, every single combination oflocals passed toa partial requires compiling another version:

<%# app/views/articles/show.html.erb %><%=renderpartial:"article",layout:"box",locals:{article:@article}%><%=renderpartial:"article",layout:"box",locals:{article:@article,theme:"dark"}%>

The above snippet will cause the partial to be compiled twice, taking more time and using more memory.

def_render_template_2323231_article_show(buffer,local_assigns,article:)# ...enddef_render_template_3243454_article_show(buffer,local_assigns,article:,theme:)# ...end

When the number of combinations is small, it's not really a problem, but if it's large it can wastea sizeable amount of memory and take a long time to compile. To counter act this you can usestrict locals to define the compiled partial signature, and ensure only a single version of the partial is compiled:

<%# locals: (article:, theme: "light") -%>...

You can enforce how many and whichlocals a template accepts, set defaultvalues, and more with alocals: signature, using the same syntax as Ruby method signatures.

Here are some examples of thelocals: signature:

<%# app/views/messages/_message.html.erb %><%# locals: (message:) -%><%=message%>

The above makesmessage a required local variable. Rendering the partialwithout a:message local variable argument will raise an exception:

render"messages/message"# => ActionView::Template::Error: missing local: :message for app/views/messages/_message.html.erb

If a default value is set then it can be used ifmessage is not passed inlocals::

<%# app/views/messages/_message.html.erb %><%# locals: (message: "Hello, world!") -%><%=message%>

Rendering the partial without a:message local variable uses the default valueset in thelocals: signature:

render"messages/message"# => "Hello, world!"

Rendering the partial with local variables not specified in thelocal: signature will also raise an exception:

render"messages/message",unknown_local:"will raise"# => ActionView::Template::Error: unknown local: :unknown_local for app/views/messages/_message.html.erb

You can allow optional local variable arguments with the double splat**operator:

<%# app/views/messages/_message.html.erb %><%# locals: (message: "Hello, world!", **attributes) -%><%=tag.p(message,**attributes)%>

Or you can disablelocals entirely by setting thelocals: to empty():

<%# app/views/messages/_message.html.erb %><%# locals: () %>

Rendering the partial withany local variable arguments will raise anexception:

render"messages/message",unknown_local:"will raise"# => ActionView::Template::Error: no locals accepted for app/views/messages/_message.html.erb

Action View will process thelocals: signature in any templating enginethat supports#-prefixed comments, and will read the signature from anyline in the partial.

Only keyword arguments are supported. Defining positional or blockarguments will raise an Action View Error at render-time.

Thelocal_assigns method does not contain default values specified in thelocal: signature. To access a local variable with a default value thatis named the same as a reserved Ruby keyword, likeclass orif, the valuescan be accessed throughbinding.local_variable_get:

<%# locals: (class: "message") %><divclass="<%=binding.local_variable_get(:class)%>">...</div>

5. Layouts

Layouts can be used to render a common view template around the results of Railscontroller actions. A Rails application can have multiple layouts that pages canbe rendered within.

For example, an application might have one layout for a logged in user andanother for the marketing part of the site. The logged in user layout mightinclude top-level navigation that should be present across many controlleractions. The sales layout for a SaaS app might include top-level navigation forthings like "Pricing" and "Contact Us" pages. Different layouts can have adifferent header and footer content.

To find the layout for the current controller action, Rails first looks for afile inapp/views/layouts with the same base name as the controller. Forexample, rendering actions from theProductsController class will useapp/views/layouts/products.html.erb.

Rails will useapp/views/layouts/application.html.erb if a controller-specific layout does not exist.

Here is an example of a simple layout inapplication.html.erb file:

<!DOCTYPE html><html><head><title><%="Your Rails App"%></title><%=csrf_meta_tags%><%=csp_meta_tag%><%=stylesheet_link_tag"application","data-turbo-track":"reload"%><%=javascript_importmap_tags%></head><body><nav><ul><li><%=link_to"Home",root_path%></li><li><%=link_to"Products",products_path%></li><!-- Additional navigation links here --></ul></nav><%=yield%><footer><p>&copy;<%=Date.current.year%> Your Company</p></footer>

In the above example layout, view content will be rendered in place of<%=yield %>, and surrounded by the same<head>,<nav>, and<footer> content.

Rails provides more ways to assign specific layouts to individual controllersand actions. You can learn more about layouts in general in theLayouts andRendering in Rails guide.

5.1. Partial Layouts

Partials can have their own layouts applied to them. These layouts are differentfrom those applied to a controller action, but they work in a similar fashion.

Let's say you're displaying an article on a page which should be wrapped in adiv for display purposes. First, you'll create a newArticle:

Article.create(body:"Partial Layouts are cool!")

In theshow template, you'll render the_article partial wrapped in thebox layout:

<%# app/views/articles/show.html.erb %><%=renderpartial:'article',layout:'box',locals:{article:@article}%>

Thebox layout simply wraps the_article partial in adiv:

<%# app/views/articles/_box.html.erb %><divclass="box"><%=yield%></div>

Note that the partial layout has access to the localarticle variable that waspassed into therender call, although it is not being used within_box.html.erb in this case.

Unlike application-wide layouts, partial layouts still have the underscoreprefix in their name.

You can also render a block of code within a partial layout instead of callingyield. For example, if you didn't have the_article partial, you could dothis instead:

<%# app/views/articles/show.html.erb %><%=render(layout:'box',locals:{article:@article})do%><div><p><%=article.body%></p></div><%end%>

Assuming you use the same_box partial from above, this would produce the sameoutput as the previous example.

5.2. Collection with Partial Layouts

When rendering collections it is also possible to use the:layout option:

<%=renderpartial:"article",collection:@articles,layout:"special_layout"%>

The layout will be rendered together with the partial for each item in thecollection. The current object and object_counter variables,article andarticle_counter in the above example, will be available in the layout as well,the same way they are within the partial.

6. Helpers

Rails provides many helper methods to use with Action View. These includemethods for:

  • Formatting dates, strings and numbers
  • Creating HTML links to images, videos, stylesheets, etc...
  • Sanitizing content
  • Creating forms
  • Localizing content

You can learn more about helpers in theAction View HelpersGuide and theAction View Form HelpersGuide.

7. Localized Views

Action View has the ability to render different templates depending on thecurrent locale.

For example, suppose you have anArticlesController with ashow action. Bydefault, calling this action will renderapp/views/articles/show.html.erb. Butif you setI18n.locale = :de, then Action View will try to render the templateapp/views/articles/show.de.html.erb first. If the localized template isn'tpresent, the undecorated version will be used. This means you're not required toprovide localized views for all cases, but they will be preferred and used ifavailable.

You can use the same technique to localize the rescue files in your publicdirectory. For example, settingI18n.locale = :de and creatingpublic/500.de.html andpublic/404.de.html would allow you to have localizedrescue pages.

See theRails Internationalization (I18n) API documentation formore details.



Back to top
[8]ページ先頭

©2009-2025 Movatter.jp