在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ Ruby/ 第三章 Rails 中的視圖
寫在后面
寫在前面
第六章 Rails 的配置及部署
第四章 Rails 中的模型
4.4 模型中的校驗(yàn)(Validates)
1.3 用戶界面(UI)設(shè)計(jì)
6.5 生產(chǎn)環(huán)境部署
3.2 表單
4.3 模型中的關(guān)聯(lián)關(guān)系(Relations)
4.5 模型中的回調(diào)(Callback)
第五章 Rails 中的控制器
4.2 深入模型查詢
5.2 控制器中的方法
6.2 緩存
3.4 模板引擎的使用
6.4 I18n
第一章 Ruby on Rails 概述
6.6 常用 Gem
1.2 Rails 文件簡(jiǎn)介
2.2 REST 架構(gòu)
2.3 深入路由(routes)
第三章 Rails 中的視圖
6.3 異步任務(wù)及郵件發(fā)送
第二章 Rails 中的資源
3.3 視圖中的 AJAX 交互

第三章 Rails 中的視圖

課程概要:

本課程講解Rails 視圖(View),內(nèi)容包括常用的輔助方法(Helper),如何使用表單(Form),AJAX在視圖中的應(yīng)用以及如何借助其他的模板引擎實(shí)現(xiàn)簡(jiǎn)潔的頁(yè)面方案。

知識(shí)點(diǎn):

  1. 布局
  2. 輔助方法
  3. 表單
  4. AJAX
  5. 模板引擎

課程背景

視圖(View)即 MVC 中的 V,也是Rails使用者最先見到的部分。在完成業(yè)務(wù)邏輯前,合理的設(shè)計(jì)視圖是 MVC 開發(fā)中最先得到用戶認(rèn)可的部分。本課程結(jié)合商品頁(yè)面的開發(fā),講解Rails 中的視圖。

3.1 布局和輔助方法

概要:

本課時(shí)講解Rails 視圖(View)中的布局文件,常見的輔助方法(Helper)以及如何使用局部模板。

知識(shí)點(diǎn):

  1. 布局(layout)
  2. 輔助方法(helper)
  3. 局部模板(partial)

正文

3.1.1 布局(layout)

本章開始,我們將進(jìn)入 Rails 的視圖(view) 的開發(fā)中。如果你對(duì) Rails 這個(gè) MVC 框架還有一些模糊的話,建議讀一讀這篇文章

Rails 是一個(gè) RESTful 風(fēng)格的 MVC 框架。

我們把第一章使用 bootswatch 創(chuàng)建的項(xiàng)目 copy 過來。現(xiàn)在,我們進(jìn)入到 app/views 這個(gè)文件夾吧。

layouts 里放的是布局文件。如果我們網(wǎng)站只有一種布局,那么一個(gè) application.html.erb 就足夠了。我們也可以為每個(gè)資源創(chuàng)建一個(gè) layout,比如 app/views/layouts/products.html.erb。

我們刪掉多余的代碼,增加一個(gè) yield 的輔助方法(helper)。

 <div class="container">
   <%= yield %>
 </div>

訪問我們的頁(yè)面,希望你會(huì)看到和我一樣的效果。如果沒有,沒關(guān)系,可以到 這里 clone 我們的代碼。

http://wiki.jikexueyuan.com/project/rails-practice/images/chapter_3/1.png" alt="" />

yield 方法可以讓 Rails 使用我們的模板(template) app/views/products/index.html.erb 填充了布局(layout)。

我們?cè)倏匆幌?app/views/layouts/application.html.erb 中的這一行:

<%= yield(:page_stylesheet) if content_for?(:page_stylesheet) %>

如果我們?cè)?app/views/products/index.html.erb 中使用 content_for 方法,可以在這個(gè)layout 的這個(gè)位置,顯示額外的內(nèi)容,比如,我們?cè)?index.html.erb 的最上面增加:

 <%= content_for :page_stylesheet do %>
 <!-- 這是 index.html.erb 里單獨(dú)使用的 -->
 <% end %>

再刷新下頁(yè)面,我們?cè)谠创a里看到:

http://wiki.jikexueyuan.com/project/rails-practice/images/chapter_3/2.png" alt="" />

在實(shí)踐開發(fā)里,我們經(jīng)常這樣做:布局中加載的是所有頁(yè)面通用的內(nèi)容和 css,js,而到了具體頁(yè)面,就通過 content_for 這個(gè)輔助方法定義自己的內(nèi)容,在我們的 application.html.erb 里,你可以找到四個(gè) content_for,這樣給我們的代碼里增加了一些靈活,也不必把所有內(nèi)容都寫到一起。

content_for? 判斷我們是否定義了這個(gè)變量。

如果我們想更改一下布局,該如何做呢?實(shí)踐中,我們的確會(huì)遇到以下幾種情形:

情形一:admin 要使用自己的布局文件 app/views/layouts/admin.html.erb

我們?cè)?admin 的 controller 里聲明它使用另一個(gè):

class AdminController < ApplicationController
  layout "admin"

通常我們把 admin 放到 module 中,而為 admin 建立一個(gè)通用的 controller,讓所有 admin 的 controller 都繼承它,這樣,我們不用反復(fù)的去定義了:

class Admin::BaseController < ApplicationController
  layout "admin"
end

class Admin::ProductsController < Admin::BaseController
end

class Admin::CommentsController < Admin::BaseController
end

情形二:為完成某個(gè)特殊操作,我們需要更改布局。

這時(shí),我們要在 action 里去變更這個(gè)布局,比如,創(chuàng)建一個(gè) Product 的時(shí)候:

def new
  @product = Product.new
  render layout: "another_layout"
end

情形三:不用布局

def edit
  render layout: false
end

3.1.2 常用的輔助方法(helper)

上一節(jié),我們已經(jīng)使用了幾個(gè)輔助方法,這里我們?cè)俳榻B幾個(gè) Layouts and Rendering in Rails 提到的 helper。

link_to

你會(huì)發(fā)現(xiàn)在頁(yè)面里最多的是 link_to 這個(gè)方法,它的參數(shù)也是蠻多的,我們來詳細(xì)講解。

我們把現(xiàn)在的 view 修改一下,把 首頁(yè) 的鏈接加上。

<%= link_to "網(wǎng)店演示", root_path, class: "navbar-brand" %>

一個(gè)稍復(fù)雜的例子:

<%= link_to "刪除", product, :method => :delete, :data => { :confirm => "點(diǎn)擊確定繼續(xù)" }, :class => 'btn btn-danger btn-xs' %>

我們可以改變 link_to 的默認(rèn)行為(GET),:method => :delete 將發(fā)送 delete 請(qǐng)求。:confirm 將會(huì)告訴瀏覽器阻止我們當(dāng)前的動(dòng)作,直到點(diǎn)擊 確定。實(shí)現(xiàn)上面兩個(gè)效果,需要引入 ujs, 在我們的 app/assets/javascripts/simplex.js[1] 中已經(jīng)為我們引入了:

//= require jquery
//= require jquery_ujs

注[1]:通常我們使用的是 application.js,但是在 1.3 中我們?cè)O(shè)計(jì)了新的主題,目前我使用的是 simplex。

寫到這里,我要推薦 http://api.rubyonrails.org/ 這里了,對(duì)于各種 Rails 本身的方法,我們可以通過查詢 api 文檔得到。如果是某個(gè) Gem 提供的方法,我們可以直接翻看它的 README 或者代碼。

一個(gè)較實(shí)用的工具 Dash,可以幫你管理每個(gè)版本 api 文檔,查詢起來也很方便。不過它是收費(fèi)的。

http://wiki.jikexueyuan.com/project/rails-practice/images/chapter_3/3.png" alt="" />

image_tag

建議你使用 api 文檔查找一下這方法,你會(huì)看到這個(gè)代碼提示:

image_tag("icon")
# => <img alt="Icon" src="/assets/icon" />
image_tag("icon.png")
# => <img alt="Icon" src="/assets/icon.png" />
image_tag("icon.png", size: "16x10", alt: "Edit Entry")
# => <img src="/assets/icon.png" width="16" height="10" alt="Edit Entry" />
image_tag("/icons/icon.gif", size: "16")
# => <img src="/icons/icon.gif" width="16" height="16" alt="Icon" />
image_tag("/icons/icon.gif", height: '32', width: '32')
# => <img alt="Icon" height="32" src="/icons/icon.gif" width="32" />
image_tag("/icons/icon.gif", class: "menu_icon")
# => <img alt="Icon" class="menu_icon" src="/icons/icon.gif" />

我們的圖片是來自 app/assets/images 的,我放了一個(gè) logo.png 在里面,你會(huì)發(fā)現(xiàn)它的地址是:http://localhost:3000/assets/logo-be2e3e66a18126c4042f84cd4aae4cb3.png。Rails 使用 sprockets-rails 來管理 app/assets 中的文件,后面章節(jié)我們會(huì)詳細(xì)介紹。

這里,我們可以關(guān)閉 be2e3e66a18126c4042f84cd4aae4cb3這種形式:

config/environments/development.rb

config.assets.digest = false

重啟我們的服務(wù),地址變?yōu)?http://localhost:3000/assets/logo.png

auto_discovery_link_tag

我們經(jīng)常在 head 里和頁(yè)面里,增加 rss 和 atom 訂閱連接,這時(shí),我們可以使用 auto_discovery_link_tag 這個(gè)輔助方法。

<head>
...
<%= auto_discovery_link_tag(:rss, {controller: "products", action: "index"}, {title: "RSS Feed"}) %>
<%= auto_discovery_link_tag(:atom, {controller: "products", action: "index"}, {title: "ATOM Feed"}) %>
...
</head>

我們也可以在頁(yè)面中增加這個(gè)連接,這在 web2.0 興起后的博客中很常見,方便我們把數(shù)據(jù)加入到訂閱中。

<%= link_to "rss", products_url(format: "rss") %>
<%= link_to "atom", products_url(format: "atom") %>

剩下的問題是, Rails 如何提供這個(gè)數(shù)據(jù),我并不想等到 controller 里再去講這個(gè)部分,讓我們現(xiàn)在開始了解下:

Rails 是會(huì)根據(jù)我們的請(qǐng)求類型,做出響應(yīng)。

如果我們請(qǐng)求的是一個(gè) http://localhost:3000/products.html,Rails 會(huì)給我們 html 的頁(yè)面,而如果我們請(qǐng)求的是 http://localhost:3000/products.rss,Rails 會(huì)自動(dòng)選擇 rss 的模板,渲染(render)后返回我們結(jié)果。http://localhost:3000/products.atom 也是一樣。 所以,我們?cè)?app/views/products/ 中增加兩個(gè)文件:index.rss.builderindex.atom.builder。

在 controller 里,如果我們想對(duì)結(jié)果做一些其他的操作,就需要增加這個(gè)代碼:

app/controllers/products_controller.rb

respond_to do |format|
  format.html
  format.rss { ... }
  format.atom { ... }
end

在這個(gè)例子中,我們并不需要改變什么,所以不用添加它。

app/views/products/index.atom.builder

atom_feed do |feed|
  feed.title "商品列表"
  feed.updated @products.maximum(:updated_at)

  @products.each do |product|
    feed.entry product, published: product.updated_at do |entry|
      entry.title product.name
      entry.content product.description
      entry.price product.price
    end
  end
end

app/views/products/index.rss.builder

xml.instruct! :xml, version: "1.0"
xml.rss version: "2.0" do
  xml.channel do
    xml.title "商品列表"
    xml.description "這是商品列表"
    xml.link products_url

    @products.each do |product|
      xml.item do
        xml.title product.name
        xml.description product.description
        xml.price product.price
        xml.link product_url(product)
        xml.guid product_url(product)
      end
    end
  end
end

再次訪問 http://localhost:3000/products.rsshttp://localhost:3000/products.atom,你會(huì)發(fā)現(xiàn)我們得到了結(jié)果。

我們用到了 .builder 這個(gè)結(jié)尾的文件,它會(huì)告訴 Rails 使用 Builder::XmlMarkup 這個(gè)庫(kù)(lib)來解析文件。所以看 rss.builder,它是按照 xml 格式寫的。atom.builder 用到了另一個(gè)輔助方法 atom_feed,寫法雖然不同,但是生成的內(nèi)容也是 xml 格式的。

scaffold 創(chuàng)建的文件里,你會(huì)看到 index.json.jbuilder,它會(huì)使用 JBuilder 這個(gè)庫(kù)來解析并生成 json 的結(jié)果。這會(huì)在后面的章節(jié)講到,你可以在 這里 先了解一下。

Railscasts.com 是所有 Rails 學(xué)習(xí)者必看的網(wǎng)站,這個(gè) 視頻 一定會(huì)幫助你理解上面的內(nèi)容。

在此,向 Ryan 致敬。

stylesheet_link_tag

<head>
<%= stylesheet_link_tag "simplex", :media => "all" %>
</head>

css 文件的引用通常放到頁(yè)面的 head 標(biāo)簽之間。這里我們引用的是 css 文件,我們也可以把它改為 .css.scss,這樣可以在里面寫一些 scss 語(yǔ)法,而不用更改我們的引用。我們?cè)?2.1.3 中已經(jīng)提到了 scss。

javascript_include_tag

...
<%= javascript_include_tag "simplex" %>
<%= yield(:page_javascript) if content_for?(:page_javascript) %>
</body>

瀏覽器是自上而下解析節(jié)點(diǎn)元素(DOM)的,所以,請(qǐng)注意我們把 js 文件加載放到頁(yè)面最下面,以免因?yàn)槟硞€(gè) js 解析問題導(dǎo)致頁(yè)面始終無法顯示。在引用完 js 庫(kù)后,我們還可以根據(jù)需要,單獨(dú)放置頁(yè)面的 :page_javascript

ActionView 還為我們提供了其他很多輔助方法,可以查看 這里

3.1.3 局部模板(partial)

DRY, Don't Repeat Yourself.不要重復(fù)自己。

為了讓我們節(jié)省更多的頁(yè)面重復(fù)代碼,我們還可以使用局部模板(partial)。打開我們的 app/views/products/index.html.erb

<% @products.each do |product| %>
  <%= render partial: "product", locals: { product: product } %>
<% end %>

這里我們使用了局部模板,partial 指定了使用哪個(gè)模板,locals 向模板里傳遞了一個(gè)變量。在 _product.html.erb 里,我們顯示具體 product 的信息。

不過這是一個(gè)老套的寫法,Rails 4 給了我們更酷的寫法:

<%= render @products %>

不過,如果需要傳遞更多的變量(locals),還是要用第一種方法,當(dāng)然,你完全可以把 each do 的代碼放到局部模板里。

我們也可以不傳遞變量到局部模板里,它可以找到 @products,看一下 new.html.erbedit.html.erb

<%= render :partial => 'form' %>

也可以直接寫:

<%= render 'form' %>

如果我們?cè)陧?yè)面加載路徑中,放置了多個(gè)同名的局部模板,它會(huì)顯示離它最近的那個(gè)。我們可以把公用較多的模板,放到一個(gè)專屬的文件夾里,比如 shared,引用的時(shí)候:

<%= render partial: "shared/product", locals: { product: product } %>

注:當(dāng)使用 locals 傳遞參數(shù)時(shí),一定要聲明 partial。

我為大家在 shared 中放置了一個(gè)同樣的 _product.html.erb,大家可以在 index.html.erb 中調(diào)用看看。

說一個(gè)實(shí)踐中經(jīng)常用到的局部模板。

我建立了一個(gè)新的文件夾 application,這里會(huì)放布局文件使用的局部模板,我放了一個(gè) _flash.html.erb,這是 flash 通知??纯次覀兊?products_controller.rb,我們?cè)诓僮鞒晒髸?huì)有提示信息,它在我們的頁(yè)面上還沒有顯示。我修改了一下 application.html.erb

 <div class="container">
   <%= render "flash" %>
   <%= yield %>
   ...

為了讓 flash 符合 bootstrap 的格式,我做了代碼調(diào)整,大家可以參考代碼。flash 是 session 的應(yīng)用,通常在 controller 的 action 間傳遞信息,讀取成功后自動(dòng)清空。如果一個(gè) flash 沒有在合適得地方讀出來,那么它將被保存到讀出為止,這會(huì)造成本不該顯示它的地方卻顯示它,所以我把 flash 放到了 layout 中,使得所有頁(yè)面都會(huì)引用它,保證它產(chǎn)生后立刻顯示,并在顯示后自動(dòng)清空。