前端工程師後端之旅(序) - 原來30天可以走這麼遠

一個月可以做很多事:可以讀一本書、可以出國旅遊、可以養成一個你想要的好習慣,我用一個月從零開始學習後端知識並獨立打造出一個購物車網站。

我是一名熱愛技術的網站工程師,最近參加了 Luka 的饅頭計畫,我給自己三十天的時間,用拆分網站的方式理解商業邏輯,自己思考使用者流程以及資料關係,從網站的前台介面,反推頁面流程設計,反推資料庫設計,最後做出整個網站前台與後台。後台甚至可以實際地使用「所見及所得編輯器」新增與編輯商品資料。

筆者實作前技術狀況

進入Web領域一年,目前是Vue.js前端工程師,對前端HTML、CSS、JS較熟,後端邏輯、MVC架構以及資料庫則是只有基本的了解。

專案目標

學習新的後端知識,完整重現目標網站功能,利用分析現有網站的方式,讓自己更容易理解,也增加實作跟規劃能力。

網站成果

你可以在這裡看到我的實作成果,以下筆記是這三十天內實作過程紀錄:

為什麼要進行這個練習

身為前端工程師,我覺得有必要說明做件事的理由。先說結論:我仍然想要繼續我的前端之路

但我希望身為一位網站工程師我能夠有規劃出符合需求網站的能力,而一個網站的核心基礎大多與後端脫不了關係。而且我認為網站概念本不分前後端,因為現今網站技術跟需要處理的細節越來越多,才讓前後端界線越來越明顯,但如果要能夠讓自己規劃以及實作的能力更得心應手,多少還是必須同時跨足兩個領域。

再加上我個人在學習上比較不喜歡一知半解,前端工程師常常以API跟後端互動,卻不會知道資料怎麼來的,怎麼放進去的,放在哪裡?對於這些疑問我無法置之不理,所以也算是今天做這個練習的主要動機之一。


觀念的轉變

一眨眼一個月就過去了,在這段時間內我利用所學新知完成完整的網站作品。在這過程中我從一開始的不知所措到最後學會可以專注完成每個階段性目標。其實一開始也沒想到可以做到這個程度,不過我我也是藉由改變一些原本的觀念來達到這個成果,我可以跟各位分享我的一些反思跟我是怎樣調整心態來看待遇到的困難跟問題。

從這中間我學到幾個觀念來維持自己的成長:

  1. 對任何資訊保持警覺
  2. 維持紀錄所學的習慣
  3. 慎選平時吸收的學習資源/環境
  4. 學會建立心態

對新資訊保持警覺

記得這段時間我每天睡醒就是開電腦看新文章,但是我有一個習慣,就是容易對眼前的疑惑追根究底,進而太過鑽牛角尖。在這次練習經驗裡,這個習慣就造成我不少困擾。不過也多虧我的mentor(Luka)在這中間給了我不少提醒,適時的調整心態,最有效的一個建議就是:

不管看了多少新的東西,記得專注解決眼前的問題

在實作期間,花在研究新技術的時間,最好都是為了解決問題,否則容易太發散,到最後根本忘了自己一開始要做什麼,而你必須有能力判斷目前正在接收的資訊是否適合現階段的學習。相信不少人在學習路上也遇到過跟我類似的問題吧,基本上只要能夠抓住這個原則,就能避免走進迷失方向的惡性循環。

維持紀錄所學的習慣

這段日子裡我不斷重複一種學習->吸收->紀錄的循環。一開始看到新的東西,腦子未必能夠馬上吸收,但是可以對這個技術有一定的了解,而透過實作來學習最大的好處就是可以得到即時的回饋。最後透過寫下筆記整理思維,也可以更確立自己的了解程度。

看文章學習- > 導入實做 -> 試著把學到的東西記錄下來寫成文章

很多人一聽到要另外花時間寫筆記就覺得很麻煩,我的建議是,不管紀錄的詳不詳細,都盡量練習把理解到的東西寫下來,可以訓練對知識的熟悉度,更重要的也同時在訓練表達能力。

慎選平時吸收的學習資源/環境

我覺得工程師這個職業就像一把刀子,就算沒有使用時也要常打磨,讓自己隨時準備好。所以對每個工程師來說,平常如何吸收新知與選擇接觸的資源就非常重要。

一個資深的開發者大多已經掌握自我學習的方法,但對於初學者來說,他最常接觸的可能是書、可能是線上課程或文章,不過與其說慎選資源不如說:

要非常慎選學習對象(導師)。

不論是文章還是課程影片的挑選,最終會影響你的還是教授這些事情的人。教學者的觀念、所做的行為會深深影響你處理事情的方式,包括學習。但一開始並不是每個人都有如此透徹的判斷力,在你還不知道教學者的好壞以前,我建議你保持自己的獨立思考,任何事自己先思考過一遍。

大家在剛進入職場學習時一定會遇到比較資深的前輩,盡情跟他學習吧!但記得對任何接收的訊息保持警惕,不要照單全收。

學會建立心態

說到學習新知識這件事情,就讓我想到一句話:「身子要軟,骨子要硬」。
有任何學習機會就儘管接受,但同時也要學會過濾那些看起來很充實但是對學習沒有幫助的事情,這裡講的不只有工作而已。同樣的時間,可以花在更有前瞻性的研究,也可以用在重複造輪子,時間是你的,一但你意識到自我價值,自然就會開始認真看待每件事情所花費的時間。


寫在最後

這個階段的目標結束了,接下來我也會繼續像這樣前進,設立短期階段性目標的學習讓我很有成就感,也讓我更了解自己在這條路上走了多遠。

同時我剛好正在尋找下一份工作,如果有興趣的可以參考我的履歷。

我的下一個目標是前端框架React,jsx的寫法很引起我的興趣,我會直接用專案開始練習,如果有人也正好要學這個框架,可以追蹤或聯絡我,也許有機會可以一起學習。

謝謝你的閱讀,希望以後我能以分享的方式繼續影響更多人,如果我的文章有幫助到你,請你幫我拍個手,讓我有動力繼續分享這類文章!

有興趣往下看的人,讓我們繼續吧!可以先看看我是怎麼從外觀了解網站的架構的。

前端工程師後端之旅(2) - 從畫面拆解,到整理User Story

在這個章節,我會說明我如何理解整個網站,並將其拆成很多一小部分功能,並整理出User Story。若對網站實作成果有興趣可參考: http://mujingtsai.site/

文章大綱:

  1. 什麼是User Story

  2. 用sketch整理網站的Flow

  3. 根據這些畫面列出 User Story

什麼是 User Story?

我們的階段性目標是寫出一套好理解且容易閱讀的功能需求,這個情況就非常適合User Story,User Story 通常是一段簡短但明確的功能描述,大多是這種句型開頭的:

(在XXX 頁面 )身為一個 XXX 我可以做 XXX ,以達到XXX 目的。

由於User Story 是以使用者角度為出發點,去描述網站需求,以及某個動作可以為使用者帶來的價值,除了可以避免商業上自我感覺良好的盲點,也非常利於工程部門跟其他非開發人員(如業務、PM、老闆、設計師)等角色的溝通,在這邊整理出來是為了讓自己在之後的階段可以隨時回來確認,確保功能跟需求的一致性。

Step1. 用sketch整理網站的Flow

網頁截圖進Sketch ,Sketch裡有link功能,
可以記錄頁面點擊事件的先後順序,以此模擬網站的行為,
此處用已經完成的網頁做練習,如果是在開發階段,則使用Wireframe即可(WireFlow)。

目標網站:
https://www.leisurecosmetics.com/

我從首頁開始,試著去點擊每個按鈕,看會導向哪一個頁面,
並拆解成一張一張截圖放進Sketch,做成User Flow

![](https://i.imgur.com/TnbcQWb.png =400x250)

![](https://i.imgur.com/n1hwrHE.png =400x250)

Step2. 列出 User Story

目標網站是標準的購物網站,先分出頁面在一個一個列出可能的情境利用User Story 來描述以下的功能:

  1. 商品 & 商品分類
  2. 文章 & 文章分類
  3. 購物車
  4. 聯絡我們(留言)
  5. 後台商品(類別)管理
  6. 後台文章(類別)管理
  7. 後台圖片上傳 + HTML編輯器

1. 商品 & 商品類別 :

  • 使用者可以進到類別列表
  • 使用者可以進入商品資訊頁並將商品加入購物車
  • 使用者將商品加入購物車之後會有Flash Message回饋

![](https://i.imgur.com/dnurv04.png =400x250)

![](https://i.imgur.com/YuAGv2c.png =400x250)

2. 文章 & 文章類別 :

  • 使用者可以瀏覽某類別的文章列表
  • 使用者可以瀏覽文章詳細內容

![](https://i.imgur.com/frtkAx6.png =400x250)

![](https://i.imgur.com/uTHcND1.png =400x250)


3. 購物車

  • 使用者可以新增/刪減商品
  • 使用者可以結帳

![](https://i.imgur.com/u7zMk6X.png =400x250)

![](https://i.imgur.com/H4DbNVW.png =400x250)

4. 聯絡我們表單

  • 使用者可以留下資料跟訊息並送出

![](https://i.imgur.com/u5EEz8P.png =400x250)

![](https://i.imgur.com/HksOBzR.png =400x200)

5. 前台登入

  • 使用者可以登入前台
  • 使用者可以登入後台

6. 後台商品(類別)管理

  • 使用者可以新增商品
  • 使用者可以刪除商品
  • 使用者可以瀏覽商品細節
  • 使用者可以瀏覽所有商品

7. 文章及文章類別管理

  • 使用者可以新增文章
  • 使用者可以刪除文章
  • 使用者可以瀏覽文章內容
  • 使用者可以瀏覽所有文章

8. 後台圖片上傳 + HTML編輯器

  • 使用者可以在編輯器內上傳圖片

檔案上傳是蠻常見的後台需求,但也是比較複雜的一項功能,要同時顧及到檔案類型限制、大小限制,以及如何讓上架流程更順暢,要讓使用者在編輯器內圖片上傳則需要javascript輔助。
(技術細節請見這裏)

在理解畫面,且整理好User Story之後,接下來我會說明如何進行下一步:

根據這些畫面去設計出網站路由並且做SEO優化處理

前端工程師後端之旅(3) - 路由設計以及Slug SEO優化

路由的設計也是開發網站時的重點之一,不同的功能及頁面,甚至資料存取方式,都會收到Route規劃的影響。
我們得先知道,網站總共有哪些頁面,才能整理出頁面和頁面之間的關係,進而設計出合適的路由,下面是根據畫面整理出來的網站架構,如果對於網站畫面拆解有興趣的,可以參考上一篇:

從畫面拆解,到整理User Story

或可參考網站成果: http://mujingtsai.site/

文章大綱:

  1. 網站 Sitemap
  2. 路由設計
  3. Slug SEO 優化

網站 Sitemap

根據該所有可到網站頁面可整理出如下面這樣的網站頁面圖,
這對確認需求有蠻大程度的幫助,討論需求時也比較不會東漏西漏:

前台Sitemap

後台Sitemap

路由設計:

原本的Route方式比較雜亂,雖然設計上算是Restful,
但route還要index.php還是不太美觀,甚至有可能影響SEO,
因此我想要設計成直觀一點的路由。

商品類別路由

/product/category/:category_id

商品路由

/product/:product_id 

新聞類別&&新聞路由

仿照product,一樣的方式,把product改為news:

/post/category/:category_id
/post/:post_id 

購物車路由

原來的購物車路由跟結帳路由被放在同一個層級下,容易令人疑惑,因此如果能夠拆開比較好:

/cart

結帳頁面

/checkout

登入頁面

  /user/login

會員資料頁:

/user/edit

Slug SEO 優化:

Slug(別名) 是在URL裡面,藉由給每一個頁面一個不重複具有識別性的資料,達到以更語意化的方式存取資料,藉此提升SEO友善度。

很多時候在某個頁面有很多相同類型的資料要存取,比如商品列表內某一筆商品資料、某一筆文章資料…,我們會透過在路由內搭配變數,利用商品id去存取,例如:

/products/:id 

而在使用上我們就可以透過「/products/12」去找到第12筆商品內容頁面。基本上只要能夠確保每個:id變數是獨一無二具有識別性的,就能透過這個路由一次性處理多筆資料。

但是這樣子的用法對SEO來說並不夠友善,要針對路由優化SEO,有一個大原則是讓URL簡短、清楚、語意化,其實在這個情況下,可以與路由搭配的識別性資料,也不一定只有id。

我們可以一筆一筆商品自己給定不重複的slug,
但不難想到,以商品來說,通常商品名稱也是不會重複的識別性資料。
所以我們可以直接用拿來搭配使用,而且這樣子一看就知道是對應到哪個頁面了。
例如:

products/categories/限時優惠

當然我們還是得做一些防止slug重複的方法,以免意外性的名稱重複導致網站無法運作,由於使用Slug通常是在資料庫商品資料表的欄位內多插入一個Slug欄位,所以必須指定資料欄位為unique,防止相同的資料被寫入第二次,以rails 來說就是在migration寫入類似:

add_column  :posts , :slug , :string , :index => { :unique => true }

以指定唯一的索引,你可以透過

http://mujingtsai.site/products/categories/新品上架

來看到我的實作成果。

前端工程師後端之旅(4) - 前端體驗優化

Outline

這個專案著重於後端資料規劃,不過在前端部分我還是有幾個覺得可以優化的地方,分別是

  1. 訊息提示
  2. 表單檢查
  3. 購物車實現方式。

訊息提示

不管是成功或是失敗,訊息回饋我們不希望用跳頁的方式,以減少server的負擔,不過以MVC框架的話用server端解決對工程師來說是比較明確。我想也許這邊可以用重要性來分,如網站底下的聯絡我們表單,就很適合用ajax送出資料,然後給予使用者提示。

像是使用者註冊跟個人資料修改這種比較重要的資料,就可以用傳統跳頁的方式,使得回饋感比較重。

頁尾聯絡表單

不跳頁的即時回饋:

結帳頁面Coupon彈跳訊息

結帳頁面的coupon因為是用ajax去確認coupon合法性,所以訊息不採用跳頁的方式。

表單錯誤檢查

表單檢查最好是前後端都做,但由前端處理可以減少server負擔,也確保資料送到server時的完整度,
這邊示範前端表單檢查:

結帳頁面

頁尾聯絡表單

購物車實現方式

原本的購物車是做在Server Side, 所以每加入一次購物車,甚至在購物車頁面增加或減少商品數量都是一次Request,使用者每點擊一下都要等待將近一秒鐘的延遲,對使用者比較不友善。

所以我將體驗改為,直到使用者結帳之前,都是使用瀏覽器Cookie記錄使用者加入購物車的商品資料;而使用者進入結帳頁面之後,我才是使用session來傳遞購物車資訊,避免商品資料被竄改,產生使用者購買錯誤商品的悲劇。

你可以在這裡看到相關的技術細節

前端工程師後端之旅(5) - 資料庫關係設計

為了讓設計時更容易溝通,常常會使用ERD來整理,ERD用圖像化的方式來規劃資料與資料之間的關係,讓開發人員可以對系統架構一目瞭然,如一對多、多對一、多對多等等常見的關係。

Outline

  1. ERD類別圖基本介紹
  2. 產品資料表
  3. 文章資料表
  4. 訂單及優惠券資料表
  5. 前後台使用者資料表

ERD 基本介紹

ERD 意思是 實體-關聯圖,Entity是用物件導向的class表示一個生活中的實體,關聯則是指資料庫的關聯。因為Ruby本來就是物件導向語言,而Rails又是用ORM對應資料表,所以用ERD可以很清楚的表示資料關係,
我們用一張表格表示一個Class,會長的像下面這樣:
![](https://i.imgur.com/4XYvaIh.png =230x200)

修飾子

表裡面裝的是在class裡面的property,前面使用符號來表示物件屬性的修飾子,分別是:

符號 屬性
+ public
- private
# protected

關係表示

關係 表示
一對多 1-------------1…* ( or * )
一對一 1-------------1
多對多 需要中介表

產品資料

因為可能會有想讓商品同時出現在兩個或更多個類別清單的情況,所以這邊我採用多對多關聯設計,資料表要實現多對多的話,則要藉由中間一張轉介表來串連:

文章資料

文章跟類別的就比較單純,一個類別可能有多個文章:

訂單資料

由於使用者在結帳時有可能會使用優惠券,所以Coupon跟訂單、以及訂單其他資訊之間必須有一對一關聯:

前台 / 後台 使用者

為了安全性考量,前後台的會員資料表應該要分開,如果共用同一張資料表,後台管理員有機會看到其他管理人的機密資料:

前端工程師後端之旅(6) - 利用爬蟲取得網站原始商品資料

為了盡可能重現目標網站,我們會需要原來的商品資料,但總不可能一筆一筆複製貼上,這時候我們就會需要爬蟲,爬蟲就是一隻去造訪網站並且分析網站回傳的資料,我們就可以只拿出我們需要部分的資料,透過爬蟲我們可以做很多數據統計的分析,比如:分析某某競爭對手電商的產品趨勢、分析PTT八卦版最常出現的用詞…等。

Python是最常見用於撰寫爬蟲的語言之一,但其實大多數語言都可以用來撰寫爬蟲,因為目前正在學習Rails,而且Ruby還能夠透過’active-record’使用ORM跟資料庫溝通,非常方便,所以今天我會用ruby來示範如何撰寫一隻爬蟲。

Outline - 流程

爬蟲從獲取資料到分析完資料之間可細分為幾個步驟:

  1. 觀察url規律
  2. 模擬送出HTTP Request
  3. 取得網站Response
  4. 分析html內容結構
  5. 取出需要的部分並整理
  6. 與資料庫取得連線
  7. 整理後存入資料庫

使用工具

要進行以上幾個動作,我們會需要幾個套件,分別是:

  • nokogiri:可以讓我們使用與jquery選擇器一樣的方式去選出html內容
  • rest-client: 可以模擬並發出http請求
  • active-record :讓我們可以使用ORM與資料庫溝通
  • pry :讓我可以下中斷並且觀察資料

觀察Url規律

既然是要拿到所有相同類型的資料,只要觀察不同筆資料間url的相異之處就可以了,如

https://www.leisurecosmetics.com/index.php?route=product/product&product_id=75
https://www.leisurecosmetics.com/index.php?route=product/product&product_id=77 

可看出改網站用product_id來識別商品。

模擬送出HTTP Request並取回html網頁結構

寫過前端ajax的人,一定常用axios.get(‘http://example.com/api/xxx’) 去送出get請求拿回資料,其實一般我們進入瀏覽器時,就是在對該網站的server送出Http的get請求,只不過跟ajax不同的是,拿回來的不是api資料,而是網站的畫面,這就是常聽到的Server Side Rendering,圖為進入youtube時所送出的Get請求。
螢幕快照 2019-01-23 上午10.42.09

接下來利用rest-client去模擬http get請求到該目標網站:

html = RestClient.get('https://www.leisurecosmetics.com/index.php?route=product/product&product_id=75')

binding.pry 下中斷並觀察取回的資料
螢幕快照 2019-01-23 上午10.54.54
我們已經把網頁的html拿到手了。

分析Html結構

透過RestClient取回資料後,接下來我們需要Nokigiri去讓我們可以很方便找到我們要的資料,他的使用方式其實就很跟jquery選擇元素的時候一樣,例如,想要選到商品title,我先觀察,商品title上面是否有唯一且具有識別性的元素?

<h2 class="text-primary">BS03 輕透底光 - 面部化妝刷具套裝</h2>

觀察到商品名是用h2包起來並且有 .text-primary 這個class, 我可以先用瀏覽器確認是不是用h2.text-primary可以只選到標題:
螢幕快照 2019-01-23 上午11.09.25

取出需要的部分並整理

太棒了!上面正好是我要的,之後我們只要用Nokogiri以同樣的方式選出該元素就行:

html = RestClient.get('https://www.leisurecosmetics.com/index.php?route=product/product&product_id=75')
doc = Nokogiri::HTML(html)
doc.css('h2.text-primary').text //===> get product title

螢幕快照 2019-01-23 上午11.16.50

用gsub方法把空白字元去掉,ruby的gsub就跟js的replace一樣都是用來代換字串:

doc.css('h2.text-primary').first.text()
        .gsub("\n","")
        .gsub("\t","")

螢幕快照 2019-01-23 上午11.22.05
拿到我要的資料。
也可以用正規表達式來匹配資料:

doc.css('.price h2').first().text.match(/(\w+)\$([\d,]+)/)[2] //get product price 

與資料庫取得連線

Ruby 的active record 其實不一定只能跟著Rails 搭配使用,反過來說,Rails也不一定要使用這套ORM(也有其他的)。這裡我們就把active record單獨拿出來使用,作為與資料庫溝通的橋樑。因為我們上面已經有require了,這邊只要直接使用他的class就可以:

ActiveRecord::Base.establish_connection({
    adapter: 'mysql2',
    encoding: 'utf8',
    database: 'leisure_development',
    username: 'your_db_username',
    password: 'your_db_password',
  })

記得資料庫的資訊要設好,否則會連不上。

存入資料庫

這邊用的資料庫要是跟Rails專案同樣的資料庫,才能夠直接讓專案使用。
最後就是依照資料表格式整理成Hash然後把需要的資料包成Hash,我把整段程式碼包成method,這個method 直接回傳商品資料:

  def parse_page(doc)
        product_name = doc.css('h2.text-primary').first.text()
        .gsub("\n","")
        .gsub("\t","")
        price = doc.css('.price h2').first().text.match(/(\w+)\$([\d,]+)/)[2]
        price_origin  = doc.css('.price .strike').first().text.match(/(\w+)\$([\d,]+)/)[2]
        discount_value = price_origin.to_i - price.to_i
        tab_content = doc.css('.tab-content')
        sku = doc.css('.condition li').first.text
        .gsub("\t","")
        .gsub("\n","").match(/:(\w+)/)[1]

        
        return {
            :name => product_name, 
            :price => price,
            :content=>tab_content,
            :discount_value=>discount_value, 
            :sku=>sku,
            :stock=> 100 , 
        }
    end 

接下來我只要用迴圈一筆一筆去送出request拿回html並且找到我要的商品訊息,就可以放進資料庫了,這裡因為不確定商品有幾筆,所以試試看從第一筆到第一百筆抓抓看,記得嘗試抓資料時在迴圈裡面要做例外處理,避免沒有資料而發生錯誤:

  def run  
        (1..100).each do |product_id|
            puts "Parsing product id : #{product_id} \n"
            product_url = "#{BASE_URL}?route=product/product&product_id=#{product_id}"
            begin
                

                html = RestClient.get(product_url)
                doc = Nokogiri::HTML(html)
                product_data = parse_page(doc)
                Product.create!(product_data)
            rescue => exception
                puts "#{exception.message}"
            end
            sleep 0.1
        end
    end

你可以在這裡看到我的網站實作成果

前端工程師後端之旅(7) - 爬上穹頂的最後一哩路:部署

什麼是部署

所有功能實作完之後,為了讓網站可以被一般使用者看到,我們必須要將程式碼放到一台有網路連接的電腦,只要有跟網路連接,就可以透過IP位址找到網站的所在位置,以前要做到這件事情還必須購買硬體主機等等昂貴的設備。

不過現在已經有許多網路主機商提供雲端虛擬主機的服務,只要花一點相對非常便宜的費用就可以連線到該主機去設定系統並且安裝需要的套件跟程式碼,這個複雜且充滿未知挑戰的最後一步我們稱為「部署」。

Outline

  1. 雲端Server 選擇
  2. 新增使用者
  3. 更新資源庫
  4. 安裝mysql
  5. 安裝rvm
  6. 使用rvm 安裝 並使用ruby
  7. 安裝Rails
  8. Clone 要部署的專案
  9. 安裝 Passenger 跟 nginx
  10. Nginx Server設定
  11. 參考教學

雲端Server 選擇

基本上這類服務都差不多,最基本就是用價錢跟使用時間來做考量,在這裡我使用的是Google的GCP服務,在GCP剛註冊的會員會給予300塊美金,並且在一年內可以使用,非常適合拿來做練習,而且我記得Google每個人最多可以開五個左右的帳號,一組用不夠…可以開兩個啊

對於怎麼建立一台主機,網路上應該有很多類似的教學,看一下教學應該半小時內可以完成,在此不多做說明。裝完主機後,透過GCP介面提供的指令,應該可以很快讓你從電腦連到該機器。

新增使用者

我們通常不會一直用root去操作跟安裝,而是會新增一個使用者後,在給予最高權限,因為每個帳號有自己個別的資料夾,如此一來可以讓系統比較好維護,而最高權限意味著可以做任何事情,當然包括把自己刪掉,所以在使用上要非常小心。

sudo adduser mujing
sudo adduser mujing sudo

切換帳號

su mujing

更新資源庫

我使用的是ubuntu系統,因此新系統安裝完時,最好更新一下系統內預設的套件管理器:

sudo apt-get update 

安裝mysql

這個Rails專案是搭配mysql資料庫開發的,因此必須安裝:

sudo apt install mysql-server

如果是在unbuntu上使用mysql 的話記得多裝個mysql client :

sudo apt-get install libmysqlclient-dev

安裝rvm

rvm 是Ruby 語言版本的管理套件,可以讓你在不同版本之間快速切換,方便管理:

curl -L https://get.rvm.io | bash

使用rvm 安裝 並使用ruby

使用的ruby是2.4.1 ,可以根據需求安裝不同版本

rvm install 2.2.3

設成預設

rvm use 2.4.1 --default

安裝Rails

走了那麼多步驟,終於可以安裝Rails啦

gem install rails --no-ri --no-rdoc 

Clone 要部署的專案

把程式碼從git server 下載到這台主機上,一般會放在github,
如這個專案的程式碼位置 https://github.com/moojing/rails-cart

下載完之後記得進入專案資料夾下 bundle install 指令,安裝專案所需要的套件,並透過rails指令把資料表產出來,記得專案裡面database.yml的資料庫使用者帳號密碼要設定對,否則會連不上Sql Server:

bundle install
rake db:create
rake db:migrate

安裝 Passenger 跟 nginx

Nginx 是一套http Server,可以讓管理者設定許多網頁相關的功能,我們這裡只需要最簡單的監聽某個port,可以讓資料跟外面溝通就行。

Passenger可以想成是Nginx的擴充模組,透過設定,讓你再啟動Nginx時一起把Rails 開起來,透過Nginx監聽某port,來與外界傳送資料跟溝通。

安裝以上兩個工具基本上不會很複雜,Passenger已經寫好教學等你去看了,只要照著操作就能安裝完Nginx跟Passenger:

https://www.phusionpassenger.com/library/install/nginx/install/oss/xenial

Nginx Server設定

安裝完之後開啟nginx 設定檔

sudo nano /etc/nginx/nginx.conf

應該可以看到passenger幫你加入這兩行,把註解打開就行:

# passenger_root /usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini;
# passenger_ruby /usr/bin/ruby;

由於nginx預設監聽80port,所有Server都是預設80port,平常你上網直接打網址的時候其實就是對到80port,
而且Server的port同時只能被一個程序佔用,所以如果想讓80port空下來,我們必須改掉他預設的設定:

打開下列的檔案,這裡是nginx預設的設定檔

sudo vim /etc/nginx/sites-available/default

把 listen 80 default_server;相關的設定註解掉:

# listen 80 default_server;
# listen [::]:80 default_server ipv6only=on;

在同樣的資料夾新增一個屬於你網站的設定檔:

sudo vim /etc/nginx/sites-available/mysite

放入相關設定:

server {
 listen 80 default_server;
 server_name http://34.80.215.175; //如果沒有domain 就放網址
 passenger_enabled on; //passenger 設定,要有才能串連rails
 passenger_app_env development; // 環境變數
 root /home/rails/rails-cart/public; // 你的rails專案資料夾的public
}

設定軟連結,

sudo ln -s /etc/nginx/sites-available/mysite /etc/nginx/sites-enabled/mysite

然後再重啟Nginx Server 就大功告成:

sudo service nginx start 

終於成功了!系統部署一般屬於DevOps的工作,當然以上都只用到非常基礎的知識而已,DevOps領域可說是博大精深,學也學不完,這只能算是淺嘗輒止,總之你可以在這裡看到我的實作成果。

參考教學

Luka’s notes - Deploy Redmine to VPS by Rails way in Ubuntu 14.04

How To Deploy a Rails App with Passenger and Nginx on Ubuntu 14.04

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×