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

鍍金池/ 教程/ Ruby/ 5.2 控制器中的方法
寫(xiě)在后面
寫(xiě)在前面
第六章 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 交互

5.2 控制器中的方法

概要

本課時(shí)講解 Controller 中的回調(diào),權(quán)限控制,及如何實(shí)現(xiàn)網(wǎng)店的購(gòu)物車和支付功能,以及使用 datatable 查看訂單數(shù)據(jù)。

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

  1. 回調(diào)
  2. 權(quán)限設(shè)置
  3. 狀態(tài)變更
  4. 支付
  5. 帶分頁(yè)的數(shù)據(jù)列表
  6. datatable

正文

5.2.1 回調(diào)

和 Model 中的回調(diào)一樣,Controller 中也有回調(diào)。Rails 4 之前,它稱作過(guò)濾器,F(xiàn)ilter,現(xiàn)在一些文檔也在使用 filter 字樣。

回調(diào)它之前的名字是 xxx_filter,但是這種稱呼很是歧義,于是在 Rails 4 中改成了 xxx_action。

Controller 中的回調(diào)有三個(gè),before,after,around。并且可以通過(guò) :only:except 指定在哪些方法上應(yīng)用該回調(diào)。

在我們的項(xiàng)目里,為了使登錄用戶才能訪問(wèn),我們?cè)?application_controller.rb 中已經(jīng)使用了一個(gè)前置回調(diào):

class ApplicationController < ActionController::Base
  ...
  before_action :authenticate_user!
  ...
end

因?yàn)槠渌?Controller 都繼承自它,所以這個(gè)前置回調(diào)會(huì)在所有 Controller 中生效。也就是說(shuō),訪問(wèn)所有頁(yè)面,都需要登錄狀態(tài)。

但是對(duì)于首頁(yè),展示頁(yè)等,可以公開(kāi)訪問(wèn)的頁(yè)面,我們需要跳過(guò)這個(gè)登錄校驗(yàn),Controller 中還可以使用 skip_before_action :xxx 跳過(guò)回調(diào)。

class ProductsController < ApplicationController
  skip_before_action :authenticate_user!, only: [:index, :show, :top]
end

回調(diào)也可以使用 block 和單獨(dú)的回調(diào)類,方法和 Model 中一樣,或者參考這里。(注:它還在用 filter 字樣)

5.2.2 權(quán)限控制

Controller 除了對(duì)請(qǐng)求作出相應(yīng),另一個(gè)重要的事情是做權(quán)限控制,只有擁有權(quán)限的用戶才可以觸發(fā)方法。權(quán)限管理有很多 gem 可用,常用的有 cancan,pundit 等。

由于 cancan 已經(jīng)兩年沒(méi)有維護(hù)了,所以Ruby社區(qū)推出cancan 的社區(qū)版 cancancan。

% rails g cancan:ability
  create  app/models/ability.rb

編輯 ability.rb,我們的權(quán)限是:當(dāng)一個(gè) user(已登錄)字段 role 是 admin 時(shí),可以管理所有資源,否則,只能管理它自己的資源。

user ||= User.new # guest user (not logged in)
if user.admin?
  can :manage, :all
else
  can :read, :all [1]
  can :manage, Address, :user_id => user.id [2]
end

[1] 非管理員可讀所有

[2] 用戶管理自己的收貨地址

我們給 users 表添加 role 字段:

rails g migration addRoleToUsers role:string

在視圖中判斷權(quán)限:

<%= link_to "Edit", edit_product_path(product) if can? :update, product %>

這里有四個(gè)動(dòng)作可以判斷::read,:create,:update:destroy。

我們?cè)?Controller 中增加 load_and_authorize_resource 回調(diào),這個(gè)回調(diào)將自動(dòng)加載一個(gè)資源,并且進(jìn)行權(quán)限校驗(yàn),這適合資源管理中的方法:

class ProductsController < ApplicationController
  load_and_authorize_resource

也可以將這個(gè)回調(diào)分成兩個(gè)回調(diào),這樣方便覆寫(xiě)其中的方法:

class ProductsController < ApplicationController
  load_resource
  authorize_resource

更多文檔詳見(jiàn) 這里

也可以不實(shí)用回調(diào),直接在方法上判斷權(quán)限,比如判斷當(dāng)前用戶是否可以創(chuàng)建商品:

class ProductsController < ApplicationController
  ...
  def create
    authorize! :create, @product
    ...

cancancan 更多用法,詳見(jiàn) wiki。

5.2.3 購(gòu)物車

購(gòu)物車有多種設(shè)計(jì)思路,有的會(huì)把信息保存在 cookie 中,有的保存在數(shù)據(jù)庫(kù)中。

我們將它保存到數(shù)據(jù)庫(kù)中,使用 CartItem 這個(gè) Model。當(dāng)向購(gòu)物車增加商品時(shí),我們將商品的商品類型(Variant)以及數(shù)量保存到購(gòu)物車中。如果再次購(gòu)買,會(huì)增加該商品類型的數(shù)量。

我們將訂單的創(chuàng)建過(guò)程分為三步,第一步:確認(rèn)購(gòu)物車,第二步:填寫(xiě)收貨地址,第三部:形成訂單,第四部:支付,第五步:支付成功后通知訂單。

為了方便管理購(gòu)物和支付流程,我把這個(gè)邏輯單獨(dú)的放置在 checkout_controller.rb。

當(dāng)我們計(jì)算購(gòu)物車和商品類型價(jià)格的時(shí)候,經(jīng)常的出現(xiàn) line_item.variant.price,這種查詢可以通過(guò) Model 中的 delegate 進(jìn)行改進(jìn):

class LineItem < ActiveRecord::Base
  ...
  delegate :price, to: :variant, prefix: true

這樣,剛才的查詢可以改為 line_item.variant_price。delegate 方法的 api 在 這里

但是,這種方法會(huì)造成過(guò)多的查詢,所以在確定使用這種方法后,我們可以使用 has_many 中的 includes 選項(xiàng):

class Order < ActiveRecord::Base
  has_many :line_items, -> { includes :variant }
end

當(dāng)我們?cè)俅尾樵?line_items 時(shí),會(huì)自動(dòng)的檢索關(guān)聯(lián)的 variant,避免多余的 sql 查詢。

我們編寫(xiě)代碼的時(shí)候,有一些代碼可能需要優(yōu)化,有一些功能還待完成,這時(shí)可以在代碼中增加特殊的注釋:

def checkout
  # OPTIMIZE
  # TODO
  # FIXME

使用 rake 命令可以查看代碼中的注解

rake notes:optimize/fixme/todo

關(guān)注購(gòu)物車的其他環(huán)節(jié),我們可以查看代碼演示,它所使用的方法,我們之前已經(jīng)介紹過(guò)了。

5.2.4 支付

訂單創(chuàng)建時(shí),它的 payment_stateconfirm,當(dāng)完成支付后,它的狀態(tài)改為 paid。這里我們使用支付寶來(lái)支付訂單。

我們需要安裝支付寶的 gem

并且增加初始配置文件 config/initializers/alipay.rb,這里需要填寫(xiě)從支付寶商家服務(wù) 申請(qǐng) 的 PID 和 KEY。

Alipay.pid = '申請(qǐng)的 PID'
Alipay.key = '申請(qǐng)的 KEY'

支付寶常用實(shí)時(shí)到賬和擔(dān)保交易,如果開(kāi)通了支付寶快捷登陸,在使用實(shí)時(shí)到賬時(shí),可以掃描二維碼支付。

支付成功后,通常設(shè)定為跳轉(zhuǎn)回訂單詳細(xì)頁(yè)面,支付寶會(huì)通過(guò)接口自動(dòng)通知 notify 方法,我們應(yīng)該在該方法中更新訂單狀態(tài),并且通知支付寶是否成功,只需 render text: "success"render text: "fail"。

這里有一份非常詳盡的支付寶集成方案,歡迎參考。

5.2.5 帶分頁(yè)的數(shù)據(jù)列表

進(jìn)入到“我的訂單”頁(yè)面,會(huì)有多條訂單記錄,這里需要對(duì)訂單進(jìn)行分頁(yè)。常用的分頁(yè) gem 是 will_paginate。因?yàn)槲覀冊(cè)谑褂?bootstrap,所以需要安裝 will_paginate-bootstrap。

分頁(yè)的代碼非常簡(jiǎn)單:

class OrdersController < ApplicationController
  ...
  def index
    @orders = Order.paginate(:page => params[:page], :per_page => 20)

頁(yè)面上:

  <div class="well">
    <%= page_entries_info @orders %>
  </div>
  <%= will_paginate @orders, renderer: BootstrapPagination::Rails %>

為了讓 page_entries_info 方法和分頁(yè)按鈕顯示中文,我們?cè)黾右粋€(gè)新的語(yǔ)言包:

config/locales/will_paginate/zh-CN.yml

除了 will_paginate,還有 kaminari,以及 datatable

5.2.6 datatable

datatable 是傳統(tǒng)分頁(yè)方法的一個(gè)極好的替代,當(dāng)數(shù)據(jù)量較多,且需要 ajax 加載數(shù)據(jù)時(shí),可以使用 server 端 datatable 實(shí)現(xiàn),具體請(qǐng)參考 示例列表

當(dāng)我們的訂單數(shù)量巨大的時(shí)候,我們需要使用 datatable 的 server-side,來(lái)減輕分頁(yè)加載時(shí)的壓力。這里有一個(gè)演示,供大家參考。