Vietnamese (Tiếng Việt) translation by Dai Phong (you can also view the original English article)
Sau khi tạo ra cấu trúc cơ bản của Hệ thống Quản lý Nội dung (CMS) và máy chủ thật sự bằng Go và Node.js, bạn đã sẵn sàng để thử một ngôn ngữ khác.
Lần này, tôi đang sử dụng ngôn ngữ Ruby để tạo ra máy chủ. Tôi thấy rằng, bằng cách tạo ra cùng một chương trình trong nhiều ngôn ngữ khác nhau, bạn bắt đầu có được những cái nhìn sâu sắc và mới mẻ về những cách tốt hơn để cài đặt chương trình. Bạn cũng thấy được nhiều cách để thêm chức năng vào chương trình. Hãy bắt đầu nào.
Thiết lập và Nạp Thư viện
Để lập trình trong Ruby, bạn sẽ cần phải có phiên bản mới nhất được cài đặt trên hệ thống của bạn. Ngày nay, nhiều hệ điều hành được cài đặt sẵn Ruby (Linux và OS X), nhưng chúng thường có phiên bản cũ hơn. Hướng dẫn này giả sử rằng bạn đã cài đặt Ruby phiên bản 2.4.
Cách dễ nhất để nâng cấp phiên bản ruby mới nhất là sử dụng RVM. Để cài đặt RVM trên Linux hoặc Mac OS X, hãy gõ lệnh sau trong terminal:
1 |
gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 |
2 |
curl -sSL https://get.rvm.io | bash -s stable |
Việc này sẽ tạo một kết nối an toàn để tải về và cài đặt RVM. Điều này sẽ cài đặt phiên bản ổn định mới nhất của Ruby. Bạn sẽ phải load lại shell của bạn để hoàn tất quá trình cài đặt.
Đối với Windows, bạn có thể tải về Windows Ruby Installer. Hiện tại, gói này được cập nhật lên phiên bản Ruby 2.2.2, một phiên bản phù hợp để chạy các thư viện và các script trong hướng dẫn này.
Một khi ngôn ngữ Ruby đã được cài đặt thành công, bây giờ bạn có thể cài đặt các thư viện. Ruby, cũng giống như Go và Node, có một trình quản lý gói để cài đặt các thư viện của bên thứ ba. Trong terminal, gõ lệnh sau:
1 |
gem install sinatra
|
2 |
gem install ruby-handlebars
|
3 |
gem install kramdown
|
4 |
gem install slim
|
Thao tác này sẽ cài đặt các thư viện Sinatra, Ruby Handlebars, Kramdown, và Slim. Sinatra là một framework ứng dụng web. Ruby Handlebars cài đặt công cụ xử lý template trong Ruby. Kramdown là thư viện chuyển đổi Markdown sang HTML. Slim là thư viện làm việc tương tự như Jade, nhưng nó không bao gồm các định nghĩa macro của Jade. Do đó, các macro được sử dụng trong các chỉ mục của News and Blog hôm nay là Jade như bình thường.
Tạo Tập tin rubyPress.rb
Trong thư mục cấp cao nhất, tạo tập tin rubyPress.rb
và thêm code sau đây. Tôi sẽ chú thích từng phần khi nó được thêm vào tập tin.
1 |
#
|
2 |
# Load the Libraries.
|
3 |
#
|
4 |
require 'sinatra' # http://www.sinatrarb.com/ |
5 |
require 'ruby-handlebars' # https://github.com/vincent-psarga/ruby-handlebars |
6 |
require 'kramdown' # http://kramdown.gettalong.org |
7 |
require 'slim' # http://slim-lang.com/ |
8 |
require 'json' |
9 |
require 'date' |
Điều đầu tiên cần làm là nạp các thư viện. Không giống với Node.js, những thư viện này không được nạp vào một biến. Các thư viện Ruby thêm các hàm của chúng vào phạm vi chương trình.
1 |
#
|
2 |
# Setup the Handlebars engine.
|
3 |
#
|
4 |
$hbs = Handlebars::Handlebars.new |
5 |
|
6 |
#
|
7 |
# HandleBars Helper: date
|
8 |
#
|
9 |
# Description: This helper returns the current date
|
10 |
# based on the format given.
|
11 |
#
|
12 |
$hbs.register_helper('date') {|context, format| |
13 |
now = Date.today |
14 |
now.strftime(format) |
15 |
}
|
16 |
|
17 |
#
|
18 |
# HandleBars Helper: cdate
|
19 |
#
|
20 |
# Description: This helper returns the given date
|
21 |
# based on the format given.
|
22 |
#
|
23 |
$hbs.register_helper('cdate') {|context, date, format| |
24 |
day = Date.parse(date) |
25 |
day.strftime(format) |
26 |
}
|
27 |
|
28 |
#
|
29 |
# HandleBars Helper: save
|
30 |
#
|
31 |
# Description: This helper expects a
|
32 |
# "|" where the name
|
33 |
# is saved with the value for future
|
34 |
# expansions. It also returns the
|
35 |
# value directly.
|
36 |
#
|
37 |
$hbs.register_helper('save') {|context, name, text| |
38 |
#
|
39 |
# If the text parameter isn't there, then it is the
|
40 |
# goPress format all combined into the name. Split it
|
41 |
# out. The parameters are not String objects.
|
42 |
# Therefore, they need converted first.
|
43 |
#
|
44 |
name = String.try_convert(name) |
45 |
if name.count("|") > 0 |
46 |
parts = name.split('|') |
47 |
name = parts[0] |
48 |
text = parts[1] |
49 |
end
|
50 |
|
51 |
#
|
52 |
# Register the new helper.
|
53 |
#
|
54 |
$hbs.register_helper(name) {|context, value| |
55 |
text
|
56 |
}
|
57 |
|
58 |
#
|
59 |
# Return the text.
|
60 |
#
|
61 |
text
|
62 |
}
|
Thư viện Handlebars được khởi tạo với các hàm trợ giúp khác nhau đã được định nghĩa. Các hàm trợ giúp được định nghĩa bao gồm date
, cdate
, và save
.
Hàm trợ giúp date
lấy ngày và giờ hiện tại, và định dạng nó theo chuỗi định dạng truyền vào hàm trợ giúp. cdate
thì tương tự ngoại trừ để truyền ngày trước tiên. Hàm trợ giúp save
cho phép bạn chỉ định một tên và giá trị. Nó tạo ra một hàm trợ giúp mới với tên name
và truyền ngược về giá trị. Điều này cho phép bạn tạo các biến được chỉ định một lần và có hiệu lực ở nhiều vị trí. Hàm này cũng lấy phiên bản Go, trong đó nhận một chuỗi với name
, '|' như một dấu phân tách, và value
.
1 |
#
|
2 |
# Load Server Data.
|
3 |
#
|
4 |
$parts = {} |
5 |
$parts = JSON.parse(File.read './server.json') |
6 |
$styleDir = Dir.getwd + '/themes/styling/' + $parts['CurrentStyling'] |
7 |
$layoutDir = Dir.getwd + '/themes/layouts/' + $parts['CurrentLayout'] |
8 |
|
9 |
#
|
10 |
# Load the layouts and styles defaults.
|
11 |
#
|
12 |
$parts["layout"] = File.read $layoutDir + '/template.html' |
13 |
$parts["404"] = File.read $styleDir + '/404.html' |
14 |
$parts["footer"] = File.read $styleDir + '/footer.html' |
15 |
$parts["header"] = File.read $styleDir + '/header.html' |
16 |
$parts["sidebar"] = File.read $styleDir + '/sidebar.html' |
17 |
|
18 |
#
|
19 |
# Load all the page parts in the parts directory.
|
20 |
#
|
21 |
Dir.entries($parts["Sitebase"] + '/parts/').select {|f| |
22 |
if !File.directory? f |
23 |
$parts[File.basename(f, ".*")] = File.read $parts["Sitebase"] + '/parts/' + f |
24 |
end
|
25 |
}
|
26 |
|
27 |
#
|
28 |
# Setup server defaults:
|
29 |
#
|
30 |
port = $parts["ServerAddress"].split(":")[2] |
31 |
set :port, port |
Phần tiếp theo của code là để nạp các yếu tố có thể được lưu vào bộ nhớ đệm của trang web. Đây là tất cả mọi thứ bên trong styles và layout cho theme của bạn và các phần tử bên trong thư mục parts
. Một biến toàn cục, $parts
, được nạp trước tiên từ tập tin server.json
. Thông tin đó sau này được sử dụng để nạp các yếu tố thích hợp cho bố cục và theme cụ thể. Công cụ xử lý template Handlebars sử dụng thông tin này để điền vào các template.
1 |
#
|
2 |
# Define the routes for the CMS.
|
3 |
#
|
4 |
get '/' do |
5 |
page "main" |
6 |
end
|
7 |
|
8 |
get '/favicon.ico', :provides => 'ico' do |
9 |
File.read "#{$parts['Sitebase']}/images/favicon.ico" |
10 |
end
|
11 |
|
12 |
get '/stylesheets.css', :provides => 'css' do |
13 |
File.read "#{$parts["Sitebase"]}/css/final/final.css" |
14 |
end
|
15 |
|
16 |
get '/scripts.js', :provides => 'js' do |
17 |
File.read "#{$parts["Sitebase"]}/js/final/final.js" |
18 |
end
|
19 |
|
20 |
get '/images/:image', :provides => 'image' do |
21 |
File.read "#{$parts['Sitebase']}/images/#{parms['image']}" |
22 |
end
|
23 |
|
24 |
get '/posts/blogs/:blog' do |
25 |
post 'blogs', params['blog'], 'index' |
26 |
end
|
27 |
|
28 |
get '/posts/blogs/:blog/:post' do |
29 |
post 'blogs', params['blog'], params['post'] |
30 |
end
|
31 |
|
32 |
get '/posts/news/:news' do |
33 |
post 'news', params['news'], 'index' |
34 |
end
|
35 |
|
36 |
get '/posts/news/:news/:post' do |
37 |
post 'news', params['news'], params['post'] |
38 |
end
|
39 |
|
40 |
get '/:page' do |
41 |
page params['page'] |
42 |
end
|
Phần tiếp theo chứa các định nghĩa cho tất cả các route. Sinatra là một máy chủ hoàn toàn tương thích với REST. Nhưng đối với CMS này, tôi sẽ chỉ sử dụng động từ get
. Mỗi route sẽ nhận các yếu tố từ route để truyền vào các hàm để tạo ra trang chính xác. Trong Sinatra, một name được đặt trước bởi dấu hai chấm xác định một phần của route để truyền đến trình xử lý route. Các yếu tố này nằm trong bảng băm params
.
1 |
#
|
2 |
# Various functions used in the making of the server:
|
3 |
#
|
4 |
|
5 |
#
|
6 |
# Function: page
|
7 |
#
|
8 |
# Description: This function is for processing a page
|
9 |
# in the CMS.
|
10 |
#
|
11 |
# Inputs:
|
12 |
# pg The page name to lookup
|
13 |
#
|
14 |
def page(pg) |
15 |
processPage $parts["layout"], "#{$parts["Sitebase"]}/pages/#{pg}" |
16 |
end
|
Hàm page
lấy tên của một trang từ route và truyền bố cục trong biến $parts
cùng với đường dẫn đầy đủ đến tập tin trang web cần thiết cho hàm processPage
. Hàm processPage
nhận thông tin này và tạo ra các trang thích hợp mà sau đó nó sẽ trả về. Trong Ruby, đầu ra của hàm trước là giá trị trả về của hàm.
1 |
#
|
2 |
# Function: post
|
3 |
#
|
4 |
# Description: This function is for processing a post type
|
5 |
# page in the CMS. All blog and news pages are
|
6 |
# post type pages.
|
7 |
#
|
8 |
# Inputs:
|
9 |
# type The type of the post
|
10 |
# cat The category of the post (blog, news)
|
11 |
# post The actual page of the post
|
12 |
#
|
13 |
def post(type, cat, post) |
14 |
processPage $parts["layout"], "#{$parts["Sitebase"]}/posts/#{type}/#{cat}/#{post}" |
15 |
end
|
Hàm post
cũng giống như hàm page
, ngoại trừ rằng hàm này hoạt động cho tất cả các trang kiểu post. Hàm này nhận type
(kiểu), cat
(danh mục) và bản thân post
. Những điều này sẽ tạo ra địa chỉ để hiển thị trang phù hợp.
1 |
#
|
2 |
# Function: figurePage
|
3 |
#
|
4 |
# Description: This function is to figure out the page
|
5 |
# type (ie: markdown, HTML, jade, etc), read
|
6 |
# the contents, and translate it to HTML.
|
7 |
#
|
8 |
# Inputs:
|
9 |
# page The address of the page
|
10 |
# without its extension.
|
11 |
#
|
12 |
def figurePage(page) |
13 |
result = "" |
14 |
|
15 |
if File.exist? page + ".html" |
16 |
#
|
17 |
# It's an HTML file.
|
18 |
#
|
19 |
result = File.read page + ".html" |
20 |
elsif File.exist? page + ".md" |
21 |
#
|
22 |
# It's a markdown file.
|
23 |
#
|
24 |
result = Kramdown::Document.new(File.read page + ".md").to_html |
25 |
|
26 |
#
|
27 |
# Fix the fancy quotes from Kramdown. It kills
|
28 |
# the Handlebars parser.
|
29 |
#
|
30 |
result.gsub!("“","\"") |
31 |
result.gsub!("”","\"") |
32 |
elsif File.exist? page + ".amber" |
33 |
#
|
34 |
# It's a jade file. Slim doesn't support
|
35 |
# macros. Therefore, not as powerful as straight jade.
|
36 |
# Also, we have to render any Handlebars first
|
37 |
# since the Slim engine dies on them.
|
38 |
#
|
39 |
File.write("./tmp.txt",$hbs.compile(File.read page + ".amber").call($parts)) |
40 |
result = Slim::Template.new("./tmp.txt").render() |
41 |
else
|
42 |
#
|
43 |
# Doesn't exist. Give the 404 page.
|
44 |
#
|
45 |
result = $parts["404"] |
46 |
end
|
47 |
|
48 |
#
|
49 |
# Return the results.
|
50 |
#
|
51 |
return result |
52 |
end
|
Hàm figurePage
sử dụng hàm processPage
để đọc nội dung của trang từ hệ thống tập tin. Hàm này nhận đường dẫn hoàn chỉnh đến tập tin không cần có phần mở rộng. figurePage
sau đó kiểm tra tập tin với tên đã cho với phần mở rộng html
để đọc một tập tin HTML. Lựa chọn thứ hai là phần mở rộng md
đối với một tập tin Markdown.
Cuối cùng, nó kiểm tra phần mở rộng amber
đối với một tập tin Jade. Hãy nhớ: Amber là tên của thư viện để xử lý tập tin có cú pháp Jade trong Go. Tôi giữ nguyên nó cho chức năng trung gian. Một tập tin HTML chỉ đơn thuần được truyền ngược lại, trong khi tất cả các tập tin Markdown và Jade được chuyển đổi sang HTML trước khi truyền ngược trở lại.
Nếu không tìm thấy tập tin, người dùng sẽ nhận được trang 404
. Bằng cách này, trang "không tìm thấy trang" của bạn trông giống như bất kỳ trang nào khác ngoại trừ nội dung.
1 |
#
|
2 |
# Function: processPage
|
3 |
#
|
4 |
# Description: The function processes a page by getting
|
5 |
# its contents, combining with all the page
|
6 |
# parts using Handlebars, and processing the
|
7 |
# shortcodes.
|
8 |
#
|
9 |
# Inputs:
|
10 |
# layout The layout structure for the page
|
11 |
# page The complete path to the desired
|
12 |
# page without its extension.
|
13 |
#
|
14 |
def processPage(layout, page) |
15 |
#
|
16 |
# Get the page contents and name.
|
17 |
#
|
18 |
$parts["content"] = figurePage page |
19 |
$parts["PageName"] = File.basename page |
20 |
|
21 |
#
|
22 |
# Run the page through Handlebars engine.
|
23 |
#
|
24 |
begin
|
25 |
pageHB = $hbs.compile(layout).call($parts) |
26 |
rescue
|
27 |
pageHB = " |
28 |
Render Error
|
29 |
|
30 |
"
|
31 |
end
|
32 |
|
33 |
#
|
34 |
# Run the page through the shortcodes processor.
|
35 |
#
|
36 |
pageSH = processShortCodes pageHB |
37 |
|
38 |
#
|
39 |
# Run the page through the Handlebar engine again.
|
40 |
#
|
41 |
begin
|
42 |
pageFinal = $hbs.compile(pageSH).call($parts) |
43 |
rescue
|
44 |
pageFinal = " |
45 |
Render Error
|
46 |
|
47 |
" + pageSH |
48 |
end
|
49 |
|
50 |
#
|
51 |
# Return the results.
|
52 |
#
|
53 |
return pageFinal |
54 |
end
|
Hàm processPage
thực hiện tất cả các việc khai triển template dựa trên dữ liệu trang. Nó bắt đầu bằng cách gọi hàm figurePage
để lấy nội dung của trang. Sau đó, nó xử lý bố cục được truyền cho nó với Handlebars để khai triển template.
Sau đó, hàm processShortCode
sẽ tìm và xử lý tất cả các shortcode bên trong trang. Kết quả sau đó được truyền cho Handlebars một lần nữa để xử lý bất kỳ macro còn lại nào bởi các shortcode. Người dùng nhận được kết quả cuối cùng.
1 |
#
|
2 |
# Function: processShortCodes
|
3 |
#
|
4 |
# Description: This function takes the page and processes
|
5 |
# all of the shortcodes in the page.
|
6 |
#
|
7 |
# Inputs:
|
8 |
# page The contents of the page to
|
9 |
# process.
|
10 |
#
|
11 |
def processShortCodes(page) |
12 |
#
|
13 |
# Initialize the result variable for returning.
|
14 |
#
|
15 |
result = "" |
16 |
|
17 |
#
|
18 |
# Find the first shortcode
|
19 |
#
|
20 |
scregFind = /\-\[([^\]]*)\]\-/ |
21 |
match1 = scregFind.match(page) |
22 |
if match1 != nil |
23 |
#
|
24 |
# We found one! get the text before it
|
25 |
# into the result variable and initialize
|
26 |
# the name, param, and contents variables.
|
27 |
#
|
28 |
name = "" |
29 |
param = "" |
30 |
contents = "" |
31 |
nameLine = match1[1] |
32 |
loc1 = scregFind =~ page |
33 |
result = page[0, loc1] |
34 |
|
35 |
#
|
36 |
# Separate out the nameLine into a shortcode
|
37 |
# name and parameters.
|
38 |
#
|
39 |
match2 = /(\w+)(.*)*/.match(nameLine) |
40 |
if match2.length == 2 |
41 |
#
|
42 |
# Just a name was found.
|
43 |
#
|
44 |
name = match2[1] |
45 |
else
|
46 |
#
|
47 |
# A name and parameter were found.
|
48 |
#
|
49 |
name = match2[1] |
50 |
param = match2[2] |
51 |
end
|
52 |
|
53 |
#
|
54 |
# Find the closing shortcode
|
55 |
#
|
56 |
rest = page[loc1+match1[0].length, page.length] |
57 |
regEnd = Regexp.new("\\-\\[\\/#{name}\\]\\-") |
58 |
match3 = regEnd.match(rest) |
59 |
if match3 != nil |
60 |
#
|
61 |
# Get the contents the tags enclose.
|
62 |
#
|
63 |
loc2 = regEnd =~ rest |
64 |
contents = rest[0, loc2] |
65 |
|
66 |
#
|
67 |
# Search the contents for shortcodes.
|
68 |
#
|
69 |
contents = processShortCodes(contents) |
70 |
|
71 |
#
|
72 |
# If the shortcode exists, run it and include
|
73 |
# the results. Otherwise, add the contents to
|
74 |
# the result.
|
75 |
#
|
76 |
if $shortcodes.include?(name) |
77 |
result += $shortcodes[name].call(param, contents) |
78 |
else
|
79 |
result += contents |
80 |
end
|
81 |
|
82 |
#
|
83 |
# process the shortcodes in the rest of the
|
84 |
# page.
|
85 |
#
|
86 |
rest = rest[loc2 + match3[0].length, page.length] |
87 |
result += processShortCodes(rest) |
88 |
else
|
89 |
#
|
90 |
# There wasn't a closure. Therefore, just
|
91 |
# send the page back.
|
92 |
#
|
93 |
result = page |
94 |
end
|
95 |
else
|
96 |
#
|
97 |
# No shortcodes. Just return the page.
|
98 |
#
|
99 |
result = page |
100 |
end
|
101 |
|
102 |
return result |
103 |
end
|
Hàm processShortCodes
nhận chuỗi đã cho, tìm kiếm từng shortcode, và chạy shortcode cụ thể với các đối số và nội dung của shortcode. Tôi cũng sử dụng thủ tục shortcode để xử lý nội dung cho các shortcode.
Một shortcode là một thẻ tương tự như HTML sử dụng -[
và ]-
để tách thẻ mở và thẻ đóng -[/
và ]-
. Thẻ mở cũng chứa các thông số cho shortcode. Do đó, ví dụ một shortcode:
1 |
-[box]- |
2 |
This is inside a box. |
3 |
-[/box]- |
Shortcode này định nghĩa shortcode box
mà không có bất kỳ tham số nào với nội dung <p>This is inside a box.</p>
. Shortcode box
bao quanh nội dung trong HTML thích hợp để tạo ra một hộp xung quanh văn bản với văn bản được canh giữa bên trong hộp. Nếu sau đó này bạn muốn thay đổi cách box
được kết xuất, thì bạn chỉ cần thay đổi định nghĩa của shortcode. Điều này tiết kiệm được rất nhiều công sức.
1 |
#
|
2 |
# Data Structure: $shortcodes
|
3 |
#
|
4 |
# Description: This data structure contains all
|
5 |
# the valid shortcodes names and the
|
6 |
# function. All shortcodes should
|
7 |
# receive the arguments and the
|
8 |
# that the shortcode encompasses.
|
9 |
#
|
10 |
$shortcodes = { |
11 |
"box" => lambda { |args, contents| |
12 |
return("#{contents}") |
13 |
},
|
14 |
'Column1'=> lambda { |args, contents| |
15 |
return("#{contents}") |
16 |
},
|
17 |
'Column2' => lambda { |args, contents| |
18 |
return("#{contents}") |
19 |
},
|
20 |
'Column1of3' => lambda { |args, contents| |
21 |
return("#{contents}") |
22 |
},
|
23 |
'Column2of3' => lambda { |args, contents| |
24 |
return("#{contents}") |
25 |
},
|
26 |
'Column3of3' => lambda { |args, contents| |
27 |
return("#{contents}") |
28 |
},
|
29 |
'php' => lambda { |args, contents| |
30 |
return("#{contents}") }, 'js' => lambda { |args, contents| return("#{contents}") }, "html" => lambda { |args, contents| return("#{contents}") }, 'css' => lambda {|args, contents| return("#{contents}") } } |
Điều cuối cùng trong tập tin là bảng băm $shortcodes
chứa các thủ tục shortcode. Đây là các shortcode đơn giản, nhưng bạn có thể tạo ra các shortcode khác phức tạp nếu bạn muốn.
Tất cả các shortcode phải chấp nhận hai tham số: args
và contents
. Các chuỗi này chứa các tham số của shortcode và nội dung mà shortcode bao quanh. Vì các shortcode nằm bên trong một bảng băm, nên tôi đã sử dụng một hàm lambda để định nghĩa chúng. Một hàm lambda là một hàm không có tên. Cách duy nhất để chạy các hàm này là từ mảng băm.
Chạy Máy chủ
Một khi bạn đã tạo ra tập tin rubyPress.rb
với các nội dung ở trên, bạn có thể chạy máy chủ với:
1 |
ruby rubyPress.rb |
Vì framework Sinatra hoạt động với cấu trúc Rack của Ruby on Rails, nên bạn có thể sử dụng Pow để chạy máy chủ. Pow sẽ cài đặt các tập tin lưu trữ của hệ thống để chạy máy chủ của bạn tại cục bộ tương tự như trên một host. Bạn có thể cài đặt Pow với Powder bằng các lệnh sau:
1 |
gem install powder
|
2 |
powder install
|
Powder là một thủ tục dòng lệnh để quản lý các trang web Pow trên máy tính của bạn. Để Pow có thể nhìn thấy trang web của bạn, bạn phải tạo một liên kết mềm đến thư mục dự án của bạn trong thư mục ~/.pow
. Nếu máy chủ nằm trong thư mục /Users/test/Documents/rubyPress
, bạn sẽ thực thi các lệnh sau:
1 |
cd ~/.pow
|
2 |
ln -s /Users/test/Documents/rubyPress rubyPress |
ln -s
tạo một liên kết mềm đến thư mục được chỉ định trước nhất, với tên được chỉ định thứ hai. Pow sau đó sẽ thiết lập một tên miền trên hệ thống của bạn bằng tên của liên kết mềm. Trong ví dụ ở trên, truy cập trang http://rubyPress.dev
trong trình duyệt sẽ tải trang từ máy chủ.
Để khởi động máy chủ, hãy gõ lệnh sau đây sau khi tạo liên kết mềm:
1 |
powder start |
Để tải lại máy chủ sau khi thực hiện một số thay đổi code, hãy gõ lệnh như sau:
1 |
powder restart |



Truy cập trang web trong trình duyệt sẽ cho ra kết quả như hình ảnh ở trên. Pow sẽ thiết lập trang web tại http://rubyPress.dev
. Cho dù bạn sử dụng phương pháp nào để khởi chạy trang web, thì bạn cũng sẽ có được một trang kết quả tương tự.
Tóm tắt
Vâng, bạn đã làm được. Một CMS khác, nhưng lần này bằng Ruby. Phiên bản này là phiên bản ngắn nhất trong tất cả các CMS được tạo ra trong loạt bài này. Hãy thực hành với code và xem bạn có thể mở rộng framework cơ bản này như thế nào nhé.