iT邦幫忙

2017 iT 邦幫忙鐵人賽
DAY 24
0
DevOps

不一樣的 CI/CD 工具:Concourse 初探系列 第 24

24 - 自訂資源 (4)

雖然想要在不做額外動作的情況下設計自訂資源,不過資源本身是無法保存狀態的。所以這篇文章會快速跑過一次用 Rails 和 Grape 這兩個套件配置簡單的伺服器的範例。

實際上使用什麼方式實作都沒有關係,這邊假設我們是開發一套遊戲,所以需要存取系統中某個版本後所有怪物的資訊。

這篇文章可以跳過,如果希望直接使用範例可以使用本次的範例專案,文章結尾也有介紹如何部署到 Heroku 上面使用。

初始化專案

rails new monster-api -d postgresql

透過 rails new 指令來新增一個專案(monster-api 是目錄名稱)

建立 Model

我們預期要儲存兩種資料:

  1. 版本資訊
  • 大改版
  • 小改版
  1. 怪物資訊
  • 名稱
  • HP
  • MP
  • 屬於哪個版本

基於上述的資訊,可以用 rails generate scaffold 快速生成樣板。

rails g scaffold version major:integer minior:integer description:text
rails g scaffold monster name:string hp:integer mp:integer version:references

建置資料庫

這是在本機開發測試時會使用到的,如果想直接使用筆者的範例可以稍微看過即可。

bundle exec rake db:create
bundle exec rake db:migrate

因為第一次使用還沒有對應的開發用資料庫,所以要先跑 rake db:create 產生,之後用 rake db:migrate 自動產生資料表。

Rails 會自動管理資料表的變動,只需要使用 DSL 配置好 Migration 檔案即可

設定網址及顯示

雖然已經可以使用的,不過為了方便起件要做一些小修改。

修改 config/router.rb 檔案,新增下面的程式碼。

root to: "versions#index"

簡單說預設首頁是 versions 的頁面,方便我們新增版本。

修改 Gemfile 在適當位置加入這一行(例如 gem "rails" 下面一行)

gem 'simple_form'

運行指令

rails generate simple_form:install

修改 app/views/monsters/_form.html.erb 作出以下調整。

把第一行的 form_for 換成 simple_form_for

然後用下面的規則替換程式碼

原始有好幾段都是這個樣子

<div class="field">
  <%= f.label :name %>
  <%= f.text_field :name %>
</div>

替換成

<div class="field">
  <%= f.input :name %>
</div>

唯一的例外是 version_id 的設定,要替換成下面這樣。

<div class="field">
    <%= f.association :version %>
  </div>

修改 app/models/version.rb 增加以下內容到 class ... end 之間。

has_many :monsters

def to_s
  "#{major}.#{minior}"
end

以上的步驟是為了讓新增怪物時比較好辨識,會得到類似下面的畫面。

http://ithelp.ithome.com.tw/upload/images/20161224/20065771SMpW7BmiSc.png

用 Rails 預設的方式是不會有下拉選單可以選擇版本的,相對來說不好使用。

設定 API

修改 Gemfile 檔案,在適當位置加入下面這行。

gem 'grape'

修改 config/application.rb 在註解(# 開頭的程式碼)加入下面這些程式碼。

config.paths.add File.join('app', 'api'), glob: File.join('**', '*.rb')
config.autoload_paths += Dir[Rails.root.join('app', 'api', '*')]

修改 config/route.rb 增加這行(像是剛剛增加的 root 下方)

mount Game::API => '/'

新增 app/api/game/api.rb 這個檔案,放入下面的程式碼。

class Game::API < Grape::API
  version :v1, using: :path
  format :json

  get :versions do
    return Version.all.map(&:to_s) if params[:major].nil? && params[:minior].nil?
    Version.where("major >= ? AND minior >= ?", params[:major] || 0, params[:minior] || 0).map(&:to_s)
  end

  params do
    requires :major, type: Fixnum
    requires :minior, type: Fixnum
  end

  put :version do
    version = Version.find_by(major: params[:major], minior: params[:minior])
    version.touch unless version.nil?
    version.as_json(only: [:major, :minior, :updated_at]) || {}
  end

  get :monsters do
    return Monster.all.pluck(:name, :hp, :mp) if params[:major].nil? && params[:minior].nil?
    versions = Version.where("major <= ? AND minior <= ?", params[:major] || 0, params[:minior] || 0)
    Monster.where(version: versions).pluck(:name, :hp, :mp)
  end
end

以上是利用 Grape 這個套件快速建構的 API 伺服器,主要支援下面這些功能。

  • /v1/versions
    • 取得所有版本
    • 取得某個版本後的版本 (check 動作)
  • /v1/monsters
    • 取得所有怪物的資訊(用 名稱 HP MP 的順序存在陣列)
    • 取得某個版本前的所有怪物 (in 動作)
  • /v1/version
    • 更新某個版本的更新時間 (put 動作)

有了上面幾個 API 我們就能個別測試三個動作對應的行為。

部署

為了方便起見,所以就採用 Heroku 部署,請先裝好 Heroku 的命令列工具。

執行以下指令建構新的 APP 在 Heroku 上。

heroku create APP_NAME

git 的方式上傳到 Heroku (會自動偵測並且安裝環境)

git push heroku master

最後在 Heroku 上對資料庫做更新(已經自動建立好 PostgreSQL 資料庫)

heroku run "rake db:migrate"

如果對 Rails 有興趣,目前網路上已經有豐富的中文資源。可以去參考並且了解以上步驟的原理。

下一篇會介紹如何實作 check 功能。


上一篇
23 - 自訂資源 (3)
下一篇
25 - 自訂資源 (5)
系列文
不一樣的 CI/CD 工具:Concourse 初探30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言