賈薇
摘要:設計一個Ruby on Rails 5框架下的視圖管理方案,在不影響系統(tǒng)安全性的前提下,滿足生產(chǎn)環(huán)境中用戶在后臺自定義視圖,高自由度定制頁面外觀并即時動態(tài)載入呈現(xiàn)的需求。
關鍵詞:Web;MVC;視圖;Ruby on Rails 5
中圖分類號:TP311? ? ? 文獻標識碼:A
文章編號:1009-3044(2022)30-0037-04
開放科學(資源服務)標識碼(OSID):
一個多站點系統(tǒng)通常由不同用戶建立并管理,涵蓋不同內容面向不同受眾;用戶對站點外觀有個性化要求。除了采用預制模板之外,高級用戶會希望系統(tǒng)提供自定義視圖功能,能夠高自由度地改變頁面布局、外觀及內容排版方式,并能無須重啟即時生效;同時不能影響系統(tǒng)的安全性。
設計一個Ruby on Rails 5框架下的自定義視圖管理方案,并在Linux系統(tǒng)中實現(xiàn),使其具有上述功能。
1 系統(tǒng)環(huán)境
開發(fā)環(huán)境為Ubuntu16.04操作系統(tǒng),Ruby on Rails 5.2.3(以下簡稱RoR),MySQL 5.7數(shù)據(jù)庫。
2 視圖
RoR遵循模型-視圖-控制器設計模式,即MVC模式。視圖是表達數(shù)據(jù)顯示邏輯的地方, 通常完成或輔助完成GUI 功能[1]。
2.1 RoR 5的視圖
RoR 5返回客戶端的完整 HTML 由 ERB 視圖文件和包裝它的布局文件,以及視圖可能引用的所有局部視圖文件組成[2]。
2.1.1 視圖模板
常用視圖模板為ERB模板,由Ruby代碼和HTML組成;<%%>標簽內為Ruby代碼,渲染后返回完整的HTML。ERB模板在RoR框架中以.erb文件的方式存儲。erb模板包含Ruby代碼,允許用戶上傳erb文件會帶來安全性問題;攻擊者上傳了一個可執(zhí)行的腳本文件,并通過此文件進行進一步的惡意操作,會造成系統(tǒng)崩潰、數(shù)據(jù)泄露等嚴重安全事件[3]。
2.1.2 局部視圖
局部視圖的作用是把渲染過程分成多個更容易管理的部分。局部視圖從模板中提取代碼片斷并保存在獨立的文件中,然后在模板中重用[2]。在視圖中使用 render 方法來渲染局部視圖:
<%= render "menu" %>
上述代碼會在當前路徑下載入_menu.html.erb 局部視圖文件并渲染。局部視圖的文件名總是以下劃線開頭,以便和普通視圖文件區(qū)分開來,但在引用局部視圖時不寫下劃線[2]。注意,此處支持相對路徑,以加載其他目錄中的局部視圖文件。同一個局部視圖文件可以多次加載,也可以在一個頁面上加載多個局部視圖文件[4]。
render方法通過locals關鍵字傳遞父視圖的參數(shù):
<%= render "menu",locals:{title: @now_title} %>
上述代碼表示將父視圖的@now_title傳遞到局部視圖,并通過title變量讀取。
2.1.3 局部布局
應用于局部視圖的布局稱為局部布局。局部布局和應用于控制器動作的全局布局不一樣,但兩者的工作方式類似[2]。即局部布局只作用于頁面的局部區(qū)域。
2.2 視圖的嵌套
局部視圖中可以加載其他的局部視圖,方法同前述。
3 定義自定義布局
通過提供布局、視圖模板與局部視圖選項讓用戶自由選擇組合,配合默認/自定義樣式文件,即可實現(xiàn)高自由度自定義頁面的效果。構造一個模型與對應的編輯器、解析方法,使用戶可以在后臺在線編輯頁面布局,并實現(xiàn)頁面外觀的動態(tài)加載。
3.1 模型
需要自定義視圖的頁面通常用于提供給普通用戶瀏覽,在CMS中即首頁、欄目頁、內容頁等[5]。創(chuàng)建模型FrontPage,用于關聯(lián)控制器與自定義視圖。FrontPage的act屬性用于關聯(lián)處理該頁面的控制器/動作,如首頁記為“site/index”,即site控制器的index動作;layout屬性用于定義該頁面使用的視圖模板;layout_params屬性用于定義視圖的詳細布局信息。
3.2 編輯
3.2.1 LAYOUT常量
為避免暴露后端文件名,F(xiàn)rontPage對象layout屬性的值應使用代字,在后端進行轉換。定義Hash類型常量LAYOUT用于存儲模板數(shù)據(jù),鍵名為代字,作為layout屬性的值;值為Hash對象,用于存儲視圖模板的屬性。LAYOUT常量結構如下:
LAYOUT= {
‘'index201801 => {
:title => '首頁模板201801',
:charset => 'UTF-8',
:view => 'index_201801',
:layout_file => 'index_201801.html',
:loop_list => true,
:img => 'data:image/gif;base64,(略……)',
:config => {:top => 5,:slide => 10,:affiche => 7,:topic => 3,},
:core_assets => ['/stylesheets/base.css','/stylesheets/index.css',(略……)],
:partial => {
'one_col_201801' => {
:title => '單行單列圖片鏈接帶標題廣告',
:charset => 'UTF-8',
:view => 'one_col_201801',
:layout_file => 'one_col_201801.html',
:img => 'data:image/gif;base64,(略……)'
},
'two_cols_201801' => {
:title => '兩列對分圖片鏈接',
:charset => 'UTF-8',
:view => 'two_cols_201801',
:layout_file => 'two_cols_201801.html',
:img => 'data:image/gif;base64,(略……)'
},
(略……)
}
},
(略……)
}
LAYOUT常量主要鍵值對含義如表1:
partial的值為Hash結構,每個鍵值對定義一個父模板可使用的局部視圖。鍵名為代字,用于識別;值為Hash類型,用于存儲局部視圖的屬性。主要鍵值對如表2:
3.2.2 編輯模塊
編輯模塊為一個html文件,與erb視圖文件一一對應,用于在后臺可視化編輯器中直觀展示頁面布局和編輯配置。編輯模塊用線框圖展示視圖的布局結構,并通過Dom屬性記錄不同區(qū)域可加載的信息類型。
圖1中左側為實際頁面,右側的編輯模塊用線框圖模擬了視圖的實際布局。其中藍色區(qū)域不可自定義,白色區(qū)域中方括號內的內容為當前配置到此區(qū)域的對象。channel表示對象為Channel類,其后表示具體選中的類實例。
學習 | 專題 |
上述代碼片段為某編輯模塊的局部,使用table結構模擬一個左右布局的頁面區(qū)域。左側樣式類名為full的TD標簽,表示一個不可自定義的區(qū)域,右側表示一個可自定義的區(qū)域。title屬性的值是區(qū)域的唯一標識符,在同一個編輯模塊中應具有唯一性;注意,此處應做好規(guī)劃并與erb視圖文件對應位置的標識符保持一致。class屬性的值用于定義該區(qū)域可展示的內容,channel表示可選擇Channel類對象,即頻道;obj表示Channel類的子對象,即文章,其后的第一個方括號表示載入子對象時調用的局部視圖名,{className}表示子對象類名,此處為News,意即此處調用_news.html.erb局部視圖并通過News對象實例渲染;方括號中的數(shù)字表示數(shù)量上限。
3.2.3 視圖編輯器
視圖編輯器是讀取、解析、生成、更新頁面配置數(shù)據(jù)的人機接口。
視圖編輯器根據(jù)LAYOUT常量加載可使用視圖,并生成可視化UI。選擇一個視圖模板后會自動載入該模板的編輯模塊,頁面腳本逐個檢查編輯模塊的每個區(qū)域:如果該區(qū)域的className不為full,則該區(qū)域可自定義,根據(jù)前述規(guī)則解析className并添加腳本動作;當該區(qū)域觸發(fā)點擊事件時,打開類選擇器,通過類選擇器為該區(qū)域配置內容。類選擇器的配置受該區(qū)域class屬性的限值,以前述代碼片段為例:channel[5]限制類選擇器只能選擇Channel實例,不可超過5個。
圖3所示類選擇器關聯(lián)Channel類對象,列出所有可選擇的對象實例;采用復選框進行勾選,深色底為已選項;此時已選擇5個選項,達到該區(qū)域上限,其他選項的復選框已處于不可選狀態(tài)。
一個視圖模板除了固定的可編輯區(qū)域外,還可以根據(jù)LAYOUT常量中對應partial鍵值載入可選擇的局部視圖;這些局部視圖可重復使用。點擊可視化按鈕可順序插入新的局部視圖;自動生成唯一字符串作為該局部視圖的唯一標識符。配置局部視圖內容的方法同上,并可對局部視圖執(zhí)行刪除、排序等操作。
視圖編輯器同步更新頁面對象配置數(shù)據(jù)front_page_layout_params和可視化顯示信息。
3.2.4 配置數(shù)據(jù)
配置數(shù)據(jù)front_page_layout_params在頁面同時以JSON對象和表單元素的形式存在,并保持同步更新。
圖4為一個經(jīng)可視化處理的front_page_layout_params數(shù)據(jù),藍框中的鍵值對為該視圖模板的固定區(qū)域;這些區(qū)域的鍵名由其編輯模塊中的title屬性定義;不同視圖模板的鍵名及鍵值對數(shù)量均有差異。loop_list鍵值對中存儲插入的局部視圖配置數(shù)據(jù)。channel代表Channel類對象,ad代表Ad類對象,1780、308為實例ID;partial_id的值表示LAYOUT常量對應視圖模板的partial值中由“one_col0_202001”鍵名指向的鍵值對,由此可定位到局部視圖文件。
視圖編輯器提交時,front_page_layout_params作為當前FrontPage實例的layout_params屬性值實現(xiàn)持久化存儲;該實例被再次編輯時,視圖編輯器根據(jù)layout_params屬性值生成JSON對象front_page_layout_params,并按配置自動載入相應視圖的編輯模塊,以優(yōu)化使用體驗。
4 應用自定義布局
4.1 根據(jù)配置數(shù)據(jù)渲染視圖
當用戶請求一個自定義布局的頁面時,控制器首先根據(jù)頁面路由找到對應的FrontPage實例,讀出視圖模板layout、配置數(shù)據(jù)layout_params等。使用JSON.parse方法將layout_params轉換為JSON對象front_page_layout_params,同時生成Hash對象@page。遍歷front_page_layout_params每個鍵值對,讀取對應實例信息并以鍵值對的形式存入@page中;鍵值對結構與front_page_layout_params類似,值中增加一個鍵名為data,值為ActiveRecord::Relation實例的鍵值對。
控制器處理完畢之后,載入視圖模板layout。按前述結構在@page中獲取相應位置的數(shù)據(jù)并渲染,代碼示例如下:
<% @page.get("data|headline|data").each do |c|%>
<%= render partial:@page.get("data|headline|view").gsub(/\{className\}/,c.get("data").first.class.to_s.downcase()) || 'news', collection:c.get("data") unless c.get("data").size == 0%>
<%end%>
對于插入的局部視圖,循環(huán)調用局部視圖并將對應的data作為參數(shù)傳入即可,代碼示例如下:
<%@page.get("data|loop_list").each do |b|%>
<%= render partial:b.get("partial"), locals:{block: b.get("blocks")}%>
<%end%>
上述代碼中,get方法為自定義的Hash實例方法,用于根據(jù)鍵名取得值,支持嵌套。
4.2 自定義樣式文件
通過應用自定義樣式文件可使頁面風格更加多樣化,同時應提供預覽功能便于調整,具體方法不再詳述。
4.3 優(yōu)化響應
此方案的數(shù)據(jù)查詢需要在控制器中全部處理完成后再渲染視圖,易造成長查詢,影響頁面響應。可采用以下方法進行優(yōu)化。
一是將同步請求改為異步請求。@page返回請求參數(shù)而非對象實例,頁面渲染完成后再通過異步請求完成內容填充。二是采用緩存降低數(shù)據(jù)庫讀取頻率。如使用memcached服務器做頁面緩存,Redis服務器做隊列緩存,并開啟數(shù)據(jù)庫緩存等,以提高系統(tǒng)響應效率。
5 結束語
通過此方案,用戶可在一個系統(tǒng)中建立多個風格迥異的站點,使用系統(tǒng)后臺高自由度定義不同頁面的外觀布局,且不影響系統(tǒng)安全性。達到了最初提出的設計要求。
參考文獻:
[1] 任中方,張華,閆明松,陳世福.MVC模式研究的綜述[J].計算機應用研究,2004,21(10):1-4,8.
[2] 武漢長樂未央網(wǎng)絡科技有限公司.Action View 概述-Ruby On Rails指南[EB/OL].(2020-10-23)[2022-03-16].https://clwy.cn/guide/pages/rails-v5-action-view-overview.
[3] 郝子希,王志軍,劉振宇.文件上傳漏洞的攻擊方法與防御措施研究[J].計算機技術與發(fā)展,2019,29(2):129-134.
[4] Hartl M.Ruby on Rails 教程[M].安道,譯.4版.北京:人民郵電出版社,2017.
[5] 李靜媛.基于Web的新聞管理系統(tǒng)的設計與實現(xiàn)[D].天津:天津大學,2007.
【通聯(lián)編輯:謝媛媛】