Rails4.1 Action View概述
来源:互联网 发布:linux mkdir -m 编辑:程序博客网 时间:2024/06/05 15:55
原文:http://guides.rubyonrails.org/action_view_overview.html
通过此篇指导,你将学到:
- l 什么是ActionView以及如何在Rails的使用它
- l 如何更合理的使用模板、局部页面和布局
- l Action View提供了哪些帮助方法以及如何自定义自己的方法
- l 如何使用本地化视图
- l 如何在Rails外使用ActionView
1 什么是Action View?
Action View和ActoinController是Action Pack的两大主要组件。在Rails,请求被Action Pack捕获后,将其分配到控制器层(执行处理逻辑)和视图层(渲染模板)。尤其是,Action Controller将负责与数据库CRUD操作的连接。Action View负责编译中的响应。
Action View模板是使用内嵌Ruby语言到HTML标签中写成的。为了避免模板中引用代码变得杂乱,针对常用的表单、日期和字符串提供了一些帮助方法。针对自己的应用,自定义合适的帮助方法也非常简单。
注:Action View的一些特性虽然与ActiveRecord联系紧密,但是这并不意味着Action View依赖于Active Record。Action View是一个独立的包,可以配合其他一些Ruby库进行使用。
2 使用Action View的Rails
对于每个控制器,在app/views目录下都有相对应的模板目录进行关联。这些被关联的视图模板通常在控制器的对应动作调用后显示。
让我们看一下,通过Rails的脚手架命令,默认创建了哪些资源:
$ bin/rails generatescaffold post[...]invoke scaffold_controllercreate app/controllers/posts_controller.rbinvoke erbcreate app/views/postscreate app/views/posts/index.html.erbcreate app/views/posts/edit.html.erbcreate app/views/posts/show.html.erbcreate app/views/posts/new.html.erbcreate app/views/posts/_form.html.erb[...]
Rails中视图有自己的命名约束。尤其是,可以从上例中看到,一些视图与控制器中的动作名称保持一致。例如对于posts_controller.rb中index动作,将使用app/views/posts中的index.html.erb模板。返回到浏览器端的HTML页面是组合了这个ERB文件和对应的布局文件以及一些局部页面的最终结果。在稍后的小节中,你将获取更多有关这三部分的只知识。
3 模板,局部页面和布局
像之前提到的,最终的HTML输出页面是由Rails的3部分元素组成:模板、局部视图和布局。下面是对各部分的简述。
3.1 模板
Avtion View模板可以通过以下几种方式编写。若模板文件名有.erb后缀,可以使用内嵌Ruby语言和HTML语言进行编写。若模板文件名有.builder后缀,将使用Builder::XmlMarkup库进行编写。
Rails支持多个模板系统,并通过文件名的后缀来分辨它们。例如,使用ERB的HTML文件将有.html.erb后缀。
3.1.1 ERB
在ERB模板中,Ruby代码被<%%>和<%= %>标签包裹着。对于<% %>标签中的代码,只执行不返回任何结果,比如条件、循环或块。而<%= %>标签中的代码,将返回你所需要的值。例如:
<h1>Names of allthe people</h1><% @people.each do |person| %>Name: <%= person.name %><br><% end %>
循环的代码写在<%%>标签中,而对名字的输出代码写在<%= %>中。注意这并非用法建议,对于常规输出中使用的puts或print将无法用于ERB模板。因此如下写法是错误的:
<%#WRONG %>
Hi, Mr. <% puts "Frodo" %>
若想去掉首尾的空格,可以使用<%- -%>替代<%和%>。
3.1.2 Builder
Buider模板相对ERB来说是更具有标志性的。该模板能够方便生成XML内容。一个被命名为xml的XmlMarkup对象将可用于以.builder为后缀的模板中。
这是一些基本的例子:
xml.em("emphasized")xml.em { xml.b("emph & bold") }xml.a("A Link", "href" => "http://rubyonrails.org")xml.target("name" => "compile", "option" =>"fast")
生成后的结果是:
<span style="white-space:pre"></span><em>emphasized</em><span style="white-space:pre"></span><em><b>emph & bold</b></em><span style="white-space:pre"></span><a href="http://rubyonrails.org">A link</a><span style="white-space:pre"></span><target option="fast" name="compile" />
对于带有块参数的方法,将被看做XML标识标签,并且其内容被看做内嵌标签。例如:
<span style="white-space:pre"></span>xml.div { <span style="white-space:pre"></span> xml.h1(@person.name) <span style="white-space:pre"></span> xml.p(@person.bio)<span style="white-space:pre"></span>}
生成的结果是:
<span style="white-space:pre"></span><div> <span style="white-space:pre"></span> <h1>DavidHeinemeier Hansson</h1> <span style="white-space:pre"></span> <p>Aproduct of Danish Design during the Winter of '79...</p><span style="white-space:pre"></span></div>
以下是在Basecamp上常使用的RSS的例子:
xml.rss("version" => "2.0", "xmlns:dc" => "http://purl.org/dc/elements/1.1/")do xml.channeldo 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 endend
3.1.3 模板缓存
默认情况下,Rails将编译模板中的方法以便渲染它。当你改变一个模板后,Rails将通过检查文件的修改时间,若在开发模式下将进行重新编译。
3.2 局部页面
局部模板——通常被称为‘partials’——是将渲染过程切分成多个可管理的块的机制。使用局部视图,你可以从你模板中将某些代码提取到单独文件中,并对这些文件进行重利用。
3.2.1 给局部视图命名
可以通过如下方式使用render方法来使用局部视图:
<%= render"menu" %>
此例子中将在调用处渲染命名为_menu.html.erb的页面。注意开始的下划线字符:为了区分局部视图和普通视图,前者遵循以下划线最为命名第一个字符的命名约束。此约束同样可用于不同的目录之前:
<%= render "shared/menu" %>
该代码将调用位于app/views/shared/_menu.html.erb的局部文件。
3.2.2 使用局部视图来简化视图模板
可将局部视图看做为等效的子程序;将视图中的细节提取到局部视图,将更利于理解。例如:
<%= 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" %>
在此例子中,_add_banner.html.erb和_footer.html.erb局部视图包含在整个应用中每个页面上通用的内容。当你在编写其他页面时,你不需要关注这些细节。
3.2.3 as和object参数
在默认情况下,ActionView::Partials::PartialRenderer在局部视图中将创建与视图模板名称一致的局部变量。如:
<%= render partial: "product" %>
在product局部视图中,需要获取@product变量,可如此写:
<%= render partial:"product", locals: {product: @product} %>
使用as参数,我们可以为局部变量设定不同的名称。例如,假如我们想用item来替代product,可以如此做:
<%= renderpartial: “product”, as: “item” %>
使用object参数,常用于声明模板中使用的具体对象;当模板中的对象在别处时(例如在不同的实例变量或在本地变量),此参数将非常有用。
例如:可将一下写法:
<%= render partial:"product", locals: {product: @item} %>
转换成:
<%= render partial: "product", object: @item %>
object和as参数可以一起使用:
<%= render partial:"product", object: @item, as: "item" %>
3.2.4 渲染集合
通常在一个模板中需要对集合进行迭代并为每个元素渲染子模板。可以通过接受数据参数的方法直接实现,该方法接受数组类型的参数并为数组中每个元素渲染局部页面。
例如此例子中渲染所有的产品对象:
<% @products.each do |product| %>
<%= render partial:"product", locals: { product: product } %>
<% end %>
可以改写成:
<%= render partial: "product", collection: @products %>
当局部视图通过此方法被调用后,视图中的单个实例将可以访问集合的成员,并使用实例的名称对视图进行渲染。在此例子中,局部视图为_product,在此视图中你可以通过product变量来获取选择的实例的数据。
你可以使用更简单的语法来渲染集合。假如@products是Product对象的集合,那么你可以使用如下写法:
<%= render @products %>
Rails将自动寻找集合中对应模型的名称,即此例子中的Product。事实上,你可以创建一个多种类型对象的集合并以这种形式进行渲染,Rails将自动选择合适的局部视图来渲染。
3.2.5 间隔区模板
你也可以使用:spacer_template参数来指定第二个局部模板,该模板将用于主模板之间渲染,如:
<%= render partial: @products, spacer_template:"product_ruler" %>
Rails将在每对_product局部视图之间渲染product_ruler局部视图(没有传入数据对象)。
3.3 布局
布局通常用于渲染Rails控制器中动作对应的共享视图。尤其,每一个Rails应用有一对全局布局用户渲染绝大多数的页面。例如,一个网站会有一个布局用于登录的用户,并且有另一个布局用于市场销售。用于已登录用户的布局,可能包含一个顶层的导航栏,此栏上应该有许多的控制器动作接口。用于软件服务应用中销售模块的布局可能会包含像‘Pricing’和‘Contact Us’之类的顶层导航。你可能希望每个布局都会有不同的展现形式。你会在Layouts and Rendering in Rails章节获取等多知识。
4 局部布局
局部视图能够有自定义的布局。此类布局不同与全局布局,但是它们原理相似。
假若我们要显示博客内容到页面上,并通过div标签来显示。
首先,需要创建一个Post对象:
Post.create(body:‘Partial Layouts are cool!”)
在show动作的模板中,调用_post局部视图进行渲染并使用box布局。
post/show.html.erb
<%=render partial: ‘post’, layout: ‘box’, locals: {post: @post} %>
在box布局中使用div标签包裹_post局部视图:
posts/_box.html.erb
<divclass=’box’>
<%=yield %>
</div>
在_post局部视图中,通过post的id属性调用div_for方法,使得div包裹post的body属性。
posts/_post.html.erb
<%=div_for(post) do %>
<p><%=post.body %></p>
<%end %>
生成的结果为:
<div class='box'>
<div id='post_1'>
<p>Partial Layouts are cool!</p>
</div>
</div>
注意局部布局可以访问传递给render的post变量。但是不像普通布局,局部布局命名仍然以下划线开始。
你也可以通过渲染代码块来调用局部布局的方式,来替代使用yield。例如,若你不想使用_post局部视图你可以如此做:
<% render(layout: 'box', locals: {post: @post}) do %>
<%= div_for(post) do %>
<p><%= post.body %></p>
<% end %>
<% end %>
假设在上例中使用相同的布局_box,那么我们得到的生成结果是一致的。
5 视图路径
暂无
6 Action View提供的帮助方法概述
WIP:并非所有的帮助方法都在这介绍。详细列表请查看APIdocument。
接下来仅是简单概述一下ActionView中常用的帮助方法。建议多多参考API document,在那里可以查找到所有的方法,但这篇是很好的开端。
6.1 RecordTagHelper
此模块主要介绍一些生成div之类容器标签的方法。这是一种通过Active Record对象来生成容器标签的快捷方式,并且它们会自动生成id和class属性。你可以遵循命名约定来调用这些容器标签,而不要去考虑应该用什么样的id和class属性。
6.1.1 content_tag_for
渲染一个容器标签并关联到你的ActiveRecord对象。
例如,对于Post类的@post实例对象,进行如下操作:
<%= content_tag_for(:tr, @post) do %>
<td><%= @post.title %></td>
<% end %>
将生成HTML输出为:
<tr id="post_1234" class="post">
<td>Hello World!</td>
</tr>
你也可以通过哈希来添加额外的HTML属性,例如:
<%=content_tag_for(:tr, @post, class: "frontpage") do %>
<td><%= @post.title %></td>
<% end %>
生成的HTML输出为:
<tr id="post_1234" class="post frontpage">
<td>HelloWorld!</td>
</tr>
你可以传入Active Record对象集合。此方法能够循环操作对象并为每个元素创建容器标签。例如,传入一个@posts对象,该对象为包含两个Post对象的数组:
<%=content_tag_for(:tr, @posts) do |post| %>
<td><%= post.title %></td>
<% end %>
生成的HTML输出为:
<tr id="post_1234" class="post">
<td>HelloWorld!</td>
</tr>
<tr id="post_1235" class="post">
<td>Rubyon Rails Rocks!</td>
</tr>
6.1.2 div_for
此方法实际上是content_tag_for的:div标签的便捷实现。你可以传入一个Active Record对象或对象集合。例如:
<%= div_for(@post, class: “frontpage”) do %>
<td><%= @post.title%></td>
<% end %>
生成的HTML结果是:
<div id="post_1234" class="postfrontpage">
<td>HelloWorld!</td>
</div>
6.2 AssetTagHelper
此模块主要介绍与资源(如图片,JS脚本,样式和初始化数据)调用相关的方法。
默认情况下,Rails链接这些资源的目录为当前主机的public文件夹,但你可以通过设置config.action_controller.asset_host来改变此路径,尤其是在config/environments/production.rb中。例如,假设你的资源主机为assets.example.com:
config.action_controller.asset_host = "assets.example.com"
image_tag("rails.png")
# => <img src="http://assets.example.com/images/rails.png"alt="Rails" />
6.2.1 register_javascript_expansion
此方法用于注册一个或多个Javascript脚本,当其符号形式传入javascript_include_tag方法自动包含这些脚本文件。这个方法主要目的是对于安装在vendor/assets/javascripts中的插件在被调用时,初始化注册所需要的Javascript脚本。
ActionView::Helpers::AssetTagHelper.register_javascript_expansionmonkey: ["head", "body", "tail"]
javascript_include_tag :monkey # =>
<scriptsrc="/assets/head.js"></script>
<scriptsrc="/assets/body.js"></script>
<scriptsrc="/assets/tail.js"></script>
6.2.2 register_stylesheet_expansion
此方法用于注册一个或多个样式文件,当其符号形式传入到stylesheet_link-tag中的时候自动包含这些文件。此方法主要用于安装在vendor/assets/stylesheets的插件被调用时初始注册包含的样式文件。
ActionView::Helpers::AssetTagHelper.register_stylesheet_expansionmonkey: ["head", "body", "tail"]
stylesheet_link_tag :monkey # =>
<linkhref="/assets/head.css"media="screen" rel="stylesheet" />
<linkhref="/assets/body.css"media="screen" rel="stylesheet" />
<linkhref="/assets/tail.css"media="screen" rel="stylesheet" />
6.2.3 auto_discovery_link_tag
返回一个可供浏览器或feed阅读器获取的链接,常用于RSS或Atome feed。
auto_discovery_link_tag(:rss, "http://www.example.com/feed.rss",{title: "RSS Feed"}) # =>
<link rel="alternate" type="application/rss+xml"title="RSS Feed" href="http://www.example.com/feed"/>
6.2.4 image_path
计算出图片资源相对于app/assets/image目录的路径。文档根目录的全路径将被传入。通常使用image_tag内部方法来创建图片路径。
image_path("edit.png") # => /assets/edit.png
若config.assets.digest设为true,那么将在每个文件名后面添加指纹码:
image_path("edit.png") # =>/assets/edit-2d1a2db63fc738690021fedb5a65b68e.png
6.2.5 image_url
计算出app/assets/images目录下图片资源的url路径。此方法通过内部调用image_path方法与当前主机或资源主机合并生成。
image_url("edit.png") # => http://www.example.com/assets/edit.png
6.2.6 image_tag
返回图片资源的image资源标签。传入的资源可以是绝对路径或文件存在app/assets/images目录下的文件:
image_tag("icon.png") # => <imgsrc="/assets/icon.png" alt="Icon" />
6.2.7 javascript_include_tag
返回包含脚本资源的HTML script标签。你能够传入当前页面包含的脚本文件的名字(.js后缀可以不写),该脚本文件须存在于app/assets/javascript目录下,否则你需要传入相对于文档根目录的相对路径。
javascript_include_tag "common" # => <scriptsrc="/assets/common.js"></script>
如果应用不使用资源通道,若要在应用中包含jQueryJavaScript库,传入:defaults作为资源文件。当使用:defaults时,若应用的app/assets/javascripts目录下存在application.js文件,该文件将被包含:
javascript_include_tag :defaults
你也能够使用:all参数包含app/assets/javascripts目录下所有的脚本文件。
javascript_include_tag :all
你也可以在一个文件中缓存多个JS文件,这样通过gzip(比较快速的压缩方法)压缩后,将减少下载脚本文件的HTTP连接数量。若ActionController::Base.perform_caching设置为true(生产模式中默认为true,开发模式中没有此项设置)时才可进行缓存。
javascript_include_tag :all, cache: true # =>
<scriptsrc="/javascripts/all.js"></script>
6.2.8 javascript_path
计算出JS资源相对于app/assets/javascripts目录的相对路径。若源文件没有后缀名,那么.js将默认被添加。文档根目录的全路径将可被传入。此方法在内部通过调用javascript_include_tag来实现。
javascript_path "common" # => /assets/common.js
6.2.9 javascript_url
计算出JS资源相对于app/assets/javascripts目录的url。此方法内部通过调用javascript_path获取路径并与当前的主机或资源主机合并生成。
javascript_url "common" # => http://www.example.com/assets/common.js
6.2.10 stylesheet_link_tag
返回传入资源的样式表链接标签。若你未传入文件后缀,将自动添加.css:
stylesheet_link_tag "application" # => <linkhref="/assets/application.css" media="screen"rel="stylesheet" />
你可以使用:all参数来包含样式资源目录下的所有样式:
stylesheet_link_tag :all
你可以缓存多个文件到一个文件中,这样通过gzip压缩后,将减少对样式表的HTTP下载连接数。只能在ActionController::Base.perform_caching设置为true的情况下(此参数只在生产环境中有效),使用缓存功能。
stylesheet_link_tag :all, cache: true
# => <link href="/assets/all.css"media="screen" rel="stylesheet" />
6.2.11 stylesheet_path
计算出样式资源相对于app/assets/stylesheets目录的相对路径。若传入的资源没有后缀,将自动添加.css后缀名。文档的根目录的全路径将被传入。此方法在内部通过stylesheet_link_tag来实现:
stylesheet_path"application" # => /assets/application.css
6.2.12 stylesheet_url
计算出传入的资源相对于app/assets/stylesheets目录的相对路径。此方法内部通过stylesheet_path获取相对路径,并和当前主机或资源主机进行合并实现。
stylesheet_url "application" #=> http://www.example.com/assets/application.css
6.3 AtomFeedHelper
6.3.1 atom_feed
通过此方法可以很方便的创建Atomefeed。以下是完整的例子:
config/routes.rb resources :postsapp/controllers/posts_controller.rbdef index @posts = Post.all respond_todo |format| format.html format.atom endendapp/view/posts/index.atom.builderatom_feed do |feed| feed.title("PostsIndex") feed.updated((@posts.first.created_at)) @posts.each do |post| feed.entry(post) do|entry| entry.title(post.title) entry.content(post.body, type: 'html') entry.author do |author| author.name(post.author_name) end end endend
6.4 BenchmarkHelper
6.4.1 benchmark
允许你测量模板中块代码的时间,并记录到日志中。将可能耗时的代码块或可能产生瓶颈的代码使用此方法进行包裹,衡量其消耗的时间。
<% benchmark "Process data files" do %>
<%= expensive_files_operation %>
<% end %>
这将添加一些诸如“Process data files(0.34523)”到日志文件中,你可以通过此信息来优化代码。
6.5 CacheHelper
6.5.1 cache
此方法用于缓存视图片段而不是全部的动作或页面。这个技术在缓存菜单列表,新主题列表,静态的HTML片段等等,非常有用。这个方法对块中包含的内容进行缓存。可查看ActionController::Caching::Fragments获取更多信息。
<% cache do %>
<%= render"shared/footer" %>
<% end %>
6.6 CaptureHelper
6.6.1 capture
此方法允许你提取部分模板赋值给变量。你可以在你模板或布局中使用这些变量。
<% @greeting = capture do %>
<p>Welcome! The date and time is <%= Time.now%></p>
<% end %>
被捕获赋值的变量可以在任何地方使用:
<html>
<head>
<title>Welcome!</title>
</head>
<body>
<%= @greeting %>
</body>
</html>
6.6.2 content_for
使用该方法来存储被标记的块,以便在以后调用。你可以在随后将存储的模板内容或布局以参数形式传入到yield方法中。
例如,已经有标准的应用布局,但是在一个特殊页面需要使用特定的布局。那么我们可以通过使用content_for方法来包含javascript到我们当前的页面中,并且不需要修改其他页面。
app/views/layouts/application.html.erb
<html>
<head>
<title>Welcome!</title>
<%= yield :special_script %>
</head>
<body>
<p>Welcome! The date and time is<%= Time.now %></p>
</body>
</html>
app/views/posts/special.html.erb
<p>This is a special page.</p>
<% content_for :special_script do %>
<script>alert('Hello!')</script>
<% end %>
6.7 DateHelper
6.7.1 date_select
返回select标签集合(年、月、日的选择下拉框),并通过关联的日期数据属性列进行初始化。
date_select("post", "published_on")
6.7.2 datetime_select
返回select标签集合(包含年、月、日、小时和分钟的选择下拉框),并通过关联时间类型的数据属性列进行初始化。
datetime_select("post", "published_on")
6.7.3 distance_of_time_in_words
得到两个时间或日期对象或秒级别时间之间的相近距离。若你想更精确的近似值,可以设置include_seconds为true。
distance_of_time_in_words(Time.now, Time.now +15.seconds) # => less than aminute
distance_of_time_in_words(Time.now, Time.now + 15.seconds,include_seconds: true) # => less than 20 seconds
6.7.4 select_date
返回html下拉标签集合(包含年、月、和日),可以通过传入的日期初始化。
# Generates a date select that defaults to the date provided (sixdays after today)
select_date(Time.today + 6.days)
# Generates a date select that defaults to today (no specified date)
select_date()
6.7.5 select_datetime
返回日期时间的html下拉选择标签集合(包含年、月、日、小时和分钟),可通过传入的日期时间初始化。
# Generates a datetime select that defaults to the datetime provided(four days after today)
select_datetime(Time.now + 4.days)
# Generates a datetime select that defaults to today (no specifieddatetime)
select_datetime()
6.7.6 select_day
返回可在1到31之间选择的下拉标签,默认以当天日期进行初始化。
# Generates a select field for days that defaults to the day for thedate provided
select_day(Time.today + 2.days)
# Generates a select field for days that defaults to the numbergiven
select_day(5)
6.7.7 select_hour
返回可在0到23之间选择的下拉标签,默认以当前小时进行初始化。
# Generates a select field for hours that defaults to the hours forthe time provided
select_hour(Time.now + 6.hours)
6.7.8 select_minute
返回可在0到23之间选择的下拉标签,默认以当前小时进行初始化。
# Generates a select field for minutes that defaults to the minutesfor the time provided.
select_minute(Time.now + 6.hours)
6.7.9 select_month
返回可在0到23之间选择的下拉标签,默认以当前小时进行初始化。
# Generates a select field for months that defaults to the currentmonth
select_month(Date.today)
6.7.10 select_second
返回可在0到59之间选择的下拉标签,默认以当前秒进行初始化。
# Generates a select field for seconds that defaults to the secondsfor the time provided
select_second(Time.now + 16.minutes)
6.7.11 select_time
返回选择时间的下拉标签集合(包含小时和分钟)。
# Generates a time select that defaults to the time provided
select_time(Time.now)
6.7.12 select_year
返回选择年份的下拉标签,以当前所选定的年份为轴,并前后提供各5个年份供选择。年份的选择范围可以通过:start_year和:end_year来设置。
# Generates a select field for five years on either side ofDate.today that defaults to the current year
select_year(Date.today)
# Generates a select field from 1900 to 2009 that defaults to thecurrent year
select_year(Date.today, start_year: 1900, end_year: 2009)
6.7.13 time_ago_in_words
与distance_of_time_in_words相似,但to_time修改为Time.now。
time_ago_in_words(3.minutes.from_now) # => 3 minutes
6.7.14 time_select
返回下拉选择标签集合(包含小时、分钟和可选的秒),并与时间数据属性列相关联。这个选择器将多个参数赋值给Active Record对象。
# Creates a time select tag that, when POSTed, will be stored in theorder variable in the submitted attribute
time_select("order", "submitted")
6.8 DebugHelper
返回pre标签并显示YAML格式的对象数据。通过此方法使得对象信息变得更易读。
my_hash = {'first' => 1, 'second' => 'two', 'third'=> [1,2,3]}
debug(my_hash)
生成结果为:
<pre class='debug_dump'>---first: 1second: twothird:- 1- 2- 3</pre>
6.9 FormHelper
表单帮助方法使得标准的HTML表单标签更易与数据模型层进行相关联创建。这些帮助方法会生成HTML的表单标签,并为每个输入框提供方法(例如,text,passoword,select等等)。当表单被提交(例如,点击提交按钮或通过javascript脚本操作提交),表单中的内容将全部放入到参数对象中并传入到控制器。
有两种类型的表单帮助方法:一些与数据模型关联;另一些则不关联。这类帮助方法处理着数据模型的相关属性;可在ActionView::Helpers::FormTagHelper文档中查看到与数据模型层不关联的例子。
此帮助方法的核心是,form_for,通过它可以创建数据模型层的表单;例如,对于Person类的数据模型,创建一个新的实例对象:
# Note: a @person variablewill have been created in the controller (e.g. @person = Person.new)<%= form_for @person, url: {action: "create"} do |f|%> <%= f.text_field :first_name %> <%= f.text_field :last_name %> <%= submit_tag 'Create' %><% end %><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">生成的HTML结果为:</span><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"></span><p><form action="/people/create" method="post"></p><p><span style="color: rgb(34, 34, 34);"> </span><input id="person_first_name" name="person[first_name]" type="text" /></p><p><span style="color: rgb(34, 34, 34);"> </span><input id="person_last_name" name="person[last_name]" type="text" /></p><p><span style="color: rgb(34, 34, 34);"> </span><input name="commit" type="submit" value="Create" /></p><p></form></p>
当此表单被提交后,提交的对象为:
{"action" => "create", "controller"=> "people", "person" => {"first_name"=> "William", "last_name" => "Smith"}}
参数哈希中有一个内嵌的person键值对,在控制器中可以通过访问params[:person]来获取值。
6.9.1 check_box
返回单选框标签,并与属性列进行关联。
# Let's say that @post.validated? is 1:
check_box("post", "validated")
# => <input type="checkbox"id="post_validated" name="post[validated]"value="1" />
# <input name="post[validated]"type="hidden" value="0" />
6.9.2 fields_for
创建具体数据模型对象的标签,与form_for相似,但是不会创建form标签。在同一个表单中,此方法适合指定具体的数据模型对象:
<%= form_for @person, url: {action: "update"} do|person_form| %> First name: <%= person_form.text_field :first_name%> Last name : <%= person_form.text_field :last_name%> <%= fields_for @person.permission do|permission_fields| %> Admin? : <%=permission_fields.check_box :admin %> <% end %><% end %>
6.9.3 file_field
返回一个关联数据属性列的上传文件输入框。
file_field(:user, :avatar)
# => <input type="file" id="user_avatar"name="user[avatar]" />
6.9.4 form_for
创建一个表单,并关联数据模型,在此表单区域可实现具体属性列的关联。
<%= form_for @post do |f| %> <%= f.label :title, 'Title' %>: <%= f.text_field :title %><br> <%= f.label :body, 'Body' %>: <%= f.text_area :body %><br><% end %>
6.9.5 hidden_field
返回隐藏的输入标签,可以关联具体的属性。
hidden_field(:user, :token)
# => <input type="hidden" id="user_token"name="user[token]" value="#{@user.token}" />
6.9.6 label
返回label标签,并可关联到具体属性上。
label(:post, :title)
# => <label for="post_title">Title</label>
6.9.7 password_field
返回输入密码的input标签,可关联属性列。
password_field(:login, :pass)
# => <input type="text" id="login_pass"name="login[pass]" value="#{@login.pass}" />
6.9.8 radio_button
返回单选按钮标签,可关联属性列。
# Let's say that @post.category returns "rails":
radio_button("post", "category","rails")
radio_button("post", "category","java")
# => <input type="radio"id="post_category_rails" name="post[category]"value="rails" checked="checked" />
# <input type="radio"id="post_category_java" name="post[category]"value="java" />
6.9.9 text_area
返回textarea标签,可设置特定的属性。
text_area(:comment, :text, size: "20x30")
# => <textarea cols="20" rows="30"id="comment_text" name="comment[text]">
# #{@comment.text}
# </textarea>
6.9.10 text_field
返回text类型的input标签,可设置特定的属性。
text_field(:post, :title)
# => <input type="text" id="post_title"name="post[title]" value="#{@post.title}" />
6.9.11 email_field
返回email类型的input标签,可设置具体的属性。
email_field(:user, :email)
# => <input type="email" id="user_email"name="user[email]" value="#{@user.email}" />
6.9.12 url_field
返回url类型的input标签,可设置具体的属性。
url_field(:user, :url)
# => <input type="url" id="user_url" name="user[url]"value="#{@user.url}" />
6.10 FormOptionsHelper
提供一些方法将不同类型的容器转变成选项标签集合。
6.10.1 collection_select
返回select和option标签,并赋以对象的类方法返回的值集合。
例如,对象的结果及方法如下:
class Post < ActiveRecord::Base belongs_to:authorendclass Author < ActiveRecord::Base has_many :posts def name_with_initial "#{first_name.first}. #{last_name}" endend
简单示例(为Post类的实例对象@post选择关联的Anthor对象):
collection_select(:post, :author_id,Author.all, :id, :name_with_initial, {prompt: true})
若@post_author.id是1,将返回如下信息:
<select name="post[author_id]"> <option value="">Pleaseselect</option> <option value="1" selected="selected">D.Heinemeier Hansson</option> <option value="2">D.Thomas</option> <option value="3">M.Clark</option></select>
6.10.2 collection_radio_buttons
返回radio_button标签,并赋以对象的类方法返回的值集合。
例如,对象的结果及方法如下:
class Post < ActiveRecord::Base belongs_to:authorendclass Author < ActiveRecord::Base has_many:posts def name_with_initial "#{first_name.first}. #{last_name}" endend
简单示例(为Post类的实例对象@post选择关联的Anthor对象):
collection_radio_buttons(:post, :author_id, Author.all, :id,:name_with_initial)
若@post_author.id是1,将返回如下信息:
<span style="white-space:pre"></span><input id="post_author_id_1" name="post[author_id]" type="radio" value="1" checked="checked" /><span style="white-space:pre"></span><label for="post_author_id_1">D. HeinemeierHansson</label><span style="white-space:pre"></span><input id="post_author_id_2" name="post[author_id]" type="radio" value="2" /><span style="white-space:pre"></span><label for="post_author_id_2">D. Thomas</label><span style="white-space:pre"></span><input id="post_author_id_3" name="post[author_id]" type="radio" value="3" /><span style="white-space:pre"></span><label for="post_author_id_3">M. Clark</label>
6.10.3 collection_check_boxes
返回check_box标签,并赋以对象的类方法返回的值集合。
例如,对象的结果及方法如下:
class Post < ActiveRecord::Base has_and_belongs_to_many :authorsend class Author < ActiveRecord::Base has_and_belongs_to_many :posts def name_with_initial "#{first_name.first}. #{last_name}" endend
简单示例(为Post类的实例对象@post选择关联的Anthor对象):
collection_check_boxes(:post, :author_ids, Author.all, :id, :name_with_initial)
若@post.author_id是1,将返回如下信息:
<input id="post_author_ids_1" name="post[author_ids][]" type="checkbox" value="1" checked="checked" /><label for="post_author_ids_1">D. Heinemeier Hansson</label><input id="post_author_ids_2" name="post[author_ids][]" type="checkbox" value="2" /><label for="post_author_ids_2">D. Thomas</label><input id="post_author_ids_3" name="post[author_ids][]" type="checkbox" value="3" /><label for="post_author_ids_3">M. Clark</label><input name="post[author_ids][]" type="hidden" value="" />
6.10.4 country_options_for_select
返回所有的国家选择标签。
6.10.5 country_select
返回指定对象方法的关联的下拉选择框,并使用country_options_for_select来生成选择列表。
6.10.6 option_groups_from_collection_for_select
返回option标签,像options_from_collection_for_select,但是通过optgroup标签基于对象参数之间的关联关系来组织他们。
例如,对象的结果及方法如下:
class Continent < ActiveRecord::Base
has_many:countries
# attribs:id, name
end
class Country < ActiveRecord::Base
belongs_to:continent
# attribs:id, name, continent_id
end
简单用法:
option_groups_from_collection_for_select(@continents, :countries,:name, :id, :name, 3)
可能的输出为:
<optgroup label="Africa">
<option value="1">Egypt</option>
<option value="4">Rwanda</option>
...
</optgroup>
<optgroup label="Asia">
<option value="3" selected="selected">China</option>
<option value="12">India</option>
<option value="5">Japan</option>
...
</optgroup>
注意:只有optgroup和option被返回,因此你仍然需要使用select标签包裹它们。
6.10.7 options_for_select
接收一个容器(哈希,数组,枚举,你的类型)并返回一个option标签包裹的字符串。
options_for_select([ "VISA", "MasterCard" ])
# => <option>VISA</option><option>MasterCard</option>
注意:只有option标签被返回,你需要使用select标签包裹它们。
6.10.8 options_from_collection_for_select
通过对collection参数的迭代,通过value_method获取value属性的值,通过text_method获取text属性的值,返回option标签包裹的字符串。
# options_from_collection_for_select(collection, value_method,text_method, selected = nil)
例如,通过对@project.people中每个person的迭代,生成选择栏:
options_from_collection_for_select(@project.people, "id","name")
# => <optionvalue="#{person.id}">#{person.name}</option>
注意:返回的只是option标签,你需要使用select标签包裹结果。
6.10.9 select
创建下拉选择列表框,和通过提供的方法和对象获取的一系列的可选选项。
例如:
select("post", "person_id", Person.all.collect{|p| [ p.name, p.id ] }, {include_blank: true})
若@post.person_id的话,将变成:
<select name="post[person_id]">
<option value=""></option>
<option value="1" selected="selected">David</option>
<option value="2">Sam</option>
<option value="3">Tobias</option>
</select>
6.10.10 time_zone_options_for_select
返回世界所有时区的可选择option标签选项。
6.10.11 time_zone_select
返回世界所有时区的下拉列表框,通过time_zone_options_for_select来生成可选标签。
time_zone_select( "user", "time_zone")
6.10.12 date_field
返回date类型的input标签,并可关联属性。
date_field("user", "dob")
6.11 FormTagHelper
提供了一些方法来不依赖ActiveRecord对象(与FormHelper不同),来创建表单标签。在创建的时候,你只需要手动提供命名和值即可。
6.11.1 check_box_tag
创建一个选择按钮。
check_box_tag 'accept'
# => <input id="accept" name="accept"type="checkbox" value="1" />
6.11.2 field_set_tag
为HTML中标签元素创建区域集合。
<%= field_set_tag do %>
<p><%= text_field_tag 'name' %></p>
<% end %>
# => <fieldset><p><input id="name"name="name" type="text" /></p></fieldset>
6.11.3 file_field_tag
创建文件上传选择框。
<%= form_tag({action:"post"}, multipart: true) do %>
<label for="file">File toUpload</label> <%= file_field_tag "file" %>
<%= submit_tag %>
<% end %>
示例输出:
file_field_tag'attachment'
# => <input id="attachment"name="attachment" type="file" />
6.11.4 form_tag
以具体的路由路径来创建一个表单。该路径可通过与ActionController::Base#url_for相似的url_for_options进行设置。
<%= form_tag '/posts' do %>
<div><%= submit_tag 'Save' %></div>
<% end %>
# => <form action="/posts"method="post"><div><input type="submit"name="submit" value="Save" /></div></form>
6.11.5 hidden_field_tag
创建一个隐藏的数据输入框,通常来保存一些无法在HTTP传输中保持的状态信息。
hidden_field_tag 'token', 'VUBJKB23UIVI1UU1VOBVI@'
# => <input id="token" name="token"type="hidden" value="VUBJKB23UIVI1UU1VOBVI@" />
6.11.6 image_submit_tag
显示指定图片作为提交按钮,点击图片即提交表单。
image_submit_tag("login.png")
# => <input src="/images/login.png"type="image" />
6.11.7 label_tag
创建标签域。
label_tag 'name'
# => <label for="name">Name</label>
6.11.8 password_field_tag
创建密码输入框,并使用标记符隐藏输入的密码。
password_field_tag 'pass'
# => <input id="pass" name="pass"type="password" />
6.11.9 radio_button_tag
创建了点选按钮;使用一组点选按钮使用相同的命名,允许用户对同组中按钮进行单选。
radio_button_tag 'gender', 'male'
# => <input id="gender_male" name="gender"type="radio" value="male" />
6.11.10 select_tag
创建下拉选择框。
select_tag "people","<option>David</option>"
# => <select id="people"name="people"><option>David</option></select>
6.11.11 submit_tag
使用传入的文本,创建提交按钮。
submit_tag "Publish this post"
# => <input name="commit" type="submit"value="Publish this post" />
6.11.12 text_area_tag
创建文本输入框;常使用textarea作为长文本的输入例如发布博客或描述信息。
text_area_tag 'post'
# => <textarea id="post"name="post"></textarea>
6.11.13 text_field_tag
创建标准的文本输入框;常使用该类文本框作为小块文本输入,如用户名或搜索框。
text_field_tag 'name'
# => <input id="name" name="name"type="text" />
6.11.14 email_field_tag
创建标准邮箱类型输入框。
email_field_tag 'email'
# => <input id="email" name="email"type="email" />
6.11.15 url_field_tag
创建标准url类型的标准输入框。
url_field_tag 'url'
# => <input id="url" name="url"type="url" />
6.11.16 date_field_tag
创建标准的日期输入框。
date_field_tag "dob"
# => <input id="dob" name="dob"type="date" />
6.12 JavaScriptHelper
提供你视图中包含Javascript的方法。
6.12.1 button_to_function
然会一个拥有onclick事件的按钮。例如:
button_to_function "Greeting", "alert('Helloworld!')"
button_to_function "Delete", "if (confirm('Really?'))do_delete()"
button_to_function "Details" do |page|
page[:details].visual_effect:toggle_slide
end
6.12.2 define_javascript_funtions
将Action PackJavascript库通过一个script标签包含。
6.12.3 escape_javascript
编码javascript中的字符,使得脚本传输后仍可执行。
6.12.4 javascript_tag
返回一个Javascript标签包裹着传入的代码。
javascript_tag "alert('All is good')"
生成的HTML为:
<script>
//<![CDATA[
alert('All is good')
//]]>
</script>
6.12.5 link_to_function
返回一个链接,该链接可触发onclick事件并返回false。
link_to_function "Greeting", "alert('Hello world!')"
# => <a onclick="alert('Hello world!'); returnfalse;" href="#">Greeting</a>
6.13 NumberHelper
提供方法将数字转换成指定格式的字符串。对手机号、货币、百分数、精度、地理位置和文件大小提供了帮助方法。
6.13.1 number_to_currency
将数字转换成货币字符串。(例如:$13.65)
number_to_currency(1234567890.50) # => $1,234,567,890.50
6.13.2 number_to_human_size
将字节形式的大小表示转换成更易读的形式;在报告文件大小的时候非常有用。
number_to_human_size(1234) # => 1.2 KB
number_to_human_size(1234567) #=> 1.2 MB
6.13.3 number_to_percentage
将数字转成百分比字符串。
number_to_percentage(100, precision:0) # => 100%
6.13.4 number_to_phone
将数字转换成美国电话号码。
number_to_phone(1235551234) # => 123-555-1234
6.13.5 number_with_delimiter
以每三位插入一个分隔符的形式格式化数字。
number_with_delimiter(12345678) # => 12,345,678
6.13.6 number_with_precision
通过具体的精度等级,来格式话数字,默认为3为有效小数。
number_with_precision(111.2345) # =>111.235
number_with_precision(111.2345, 2) # => 111.23
6.14 SanitizeHelper
该模块提供了一些方法,这些方法用于净化文本中不希望存在的HTML元素。
6.14.1 sanitize
该方法将对html进行编码,去除所有不允许的属性。
sanitize @article.body
若:attributes或:tags参数被传入,只有这些被传入的标签和属性可以通过,其他都想被去除。
sanitize@article.body, tags: %w(table tr td), attributes: %w(id class style)
通过以下途径可以更改默认的过滤设置,例如在默认的列表中添加table标签:
class Application <Rails::Application
config.action_view.sanitized_allowed_tags= 'table', 'tr', 'td'
end
6.14.2 sanitize_css(style)
净化CSS代码块。
6.14.3 strip_links(html)
从链接标签中剥去其他元素,直流链接的文本。
例1:
strip_links("<a href="http://rubyonrails.org">Rubyon Rails</a>")
# => Ruby on Rails
例2:
strip_links("emailsto <a href="mailto:me@email.com">me@email.com</a>.")
# => emails to me@email.com.
例3:
strip_links('Blog: <a href="http://myblog.com/">Visit</a>.')
# => Blog: Visit.
6.14.4 strip_tags(html)
从html文本中剥去所有的HTML标签,包括注释。这个通常用于html扫描分词器,因此HTML的解析能力被html扫描器限制。
strip_tags("Strip <i>these</i> tags!")
# => Strip these tags!
strip_tags("<b>Bold</b> no more! <ahref='more.html'>See more</a>")
# => Bold no more! See more
注:输出可能仍然包含有未逃逸的字符’<’,’>’,’&’字符并迷惑浏览器。
7 本地化视图
Action View有能力渲染根据不同的地址位置渲染不同的模板。
例如,假设你的PostsController下有show动作。默认情况下,调用此动作将渲染app/views/posts/show.html.erb页面。但是,你若设置了I18n.locale= :de,那么将渲染app/views/posts/show.de.html.erb。若本地化模板不存在,未本地化的模板将会调用。这就意味着你不需要提供为所有情况提供本地化模板,你只需要提供你所需要的本地化模板即可。
你能够用同样的技术去本地化你public目录下的错误页面。例如,若设置了I18n.locale = :de并创建了public/500.de.html和public/404.de.html,将允许你使用本地化的错误页面。
自从Rails不限制I18n.locale时的符号,你能够利用此机制来根据你的需求显示不同的内容。例如,假设你有一些专家用户,这些用户可以看到普通用户无法看到的特殊页面。那么你可以如此的配置app/controller/application.rb:
before_action:set_expert_locale
def set_expert_locale
I18n.locale= :expert if current_user.expert?
end
然会你可以通过创建特定的视图,如app/views/posts/show.expert.html.erb来显示专家用户可查看的内容。
你可以在RailsInternationalization(I18n) API章节获取更多信息。- Rails4.1 Action View概述
- Rails4.1 Action Controller 概述
- Rails4.1:Active Record Basics
- Rails4.1 调试Rails应用
- Action View
- Action Provider 和Action View
- rails4 在页面view用link_to 给控制器controller传参数
- 搭建rails开发环境(ruby2.1+rails4.1.6)
- view改变跳转action
- ActionBar - Action View
- Action View layout
- 添加Action View
- JUnit in Action 2nd Edition 第一章 JUnit 概述 (1)
- Android 视图(View)概述
- Android 视图(View)概述
- Android View概述
- View编程引导(官文)——1 概述
- 关于Action&View一点代码
- 获取JDBC中的ResultSet的记录的条数
- 网页背景设置
- Python之道(一)之安装Python
- DIV+CSS例子
- opencv排错总结
- Rails4.1 Action View概述
- struts2基本配置
- struts2笔记
- Struts2几种传值
- FCKeditor的jsp版(简单版)
- Java统计数据库表中记录数
- Java中的==和equals
- javaScript 删除确认
- MySQL导出数据库