← 上一章:類別(Class)與模組(Module) 下一章:Model、View、Controller 三分天下 →

使用套件(Gem)讓開發更有效率

在開放原始碼的世界,有非常多厲害開發者願意無私的貢獻程式碼,而這些程式碼大多會打包成好用的套件,在 Ruby 的世界,我們稱它為 Gem。所有 Gem 的詳細資訊,都可在 RubyGems 網站上找得到:

image

安裝套件

在 Ruby 要安裝套件相當簡單,只要 gem install 指令加上套件的名字,敲完按下 Enter 鍵,就自動會從網路下載套件、安裝套件,一氣呵成。例如我想安裝一個名為 takami 的套件:

$ gem install takami
Fetching: takami-0.0.1.gem (100%)
Successfully installed takami-0.0.1
Parsing documentation for takami-0.0.1
Installing ri documentation for takami-0.0.1
Done installing documentation for takami after 0 seconds
1 gem installed

如果該套件又有需要其它套件,它也會一併順便一起下載、安裝。這個 takami 是我自己寫的 Gem,裡面沒有任何功能,僅是上課時教同學們怎麼把程式碼打包成 Gem 的範例,所以可安心安裝!(咦?!)

所以我說那個套件呢?

安裝 Gem 很簡單,但安裝好了之的那些檔案放哪去了?執行 gem env 可列出目前在這台電腦的設定:

$ gem env
RubyGems Environment:
  - RUBYGEMS VERSION: 2.6.11
  - RUBY VERSION: 2.4.1 (2017-03-22 patchlevel 111) [x86_64-darwin16]
  - INSTALLATION DIRECTORY: /Users/eddie/.rvm/gems/ruby-2.4.1
  - USER INSTALLATION DIRECTORY: /Users/eddie/.gem/ruby/2.4.0
  - RUBY EXECUTABLE: /Users/eddie/.rvm/rubies/ruby-2.4.1/bin/ruby
  - EXECUTABLE DIRECTORY: /Users/eddie/.rvm/gems/ruby-2.4.1/bin
  - SPEC CACHE DIRECTORY: /Users/eddie/.gem/specs
  - SYSTEM CONFIGURATION DIRECTORY: /Users/eddie/.rvm/rubies/ruby-2.4.1/etc
  - RUBYGEMS PLATFORMS:
    - ruby
    - x86_64-darwin-16
  ... 略 ...

那個 INSTALLATION DIRECTORY 就是 Gem 安裝的地方,裡面找一下應該就可以找到剛剛安裝的 takami 套件了。因為我是使用 RVM,所以 Gem 的安裝路徑會在 .rvm 目錄裡。

使用 Gem

Gem 裝好了要怎麼使用呢?剛好趁這個機會介紹一個我很喜歡的 Gem:Faker。這個套件可以快速的產生很多種的看起來像真的「假資料」。

安裝一下套件:

$ gem install faker

安裝完成之後,開 Ruby 內附的互動小工具 irb 來試玩一下:

$ irb
# 先 require 這個套件
>> require 'faker'
=> true

# 產生假的 Email
>> Faker::Internet.email
=> "lynn.raynor@grahamcartwright.net"

>> Faker::Internet.email
=> "guiseppe@jones.net"

# 連權利遊戲(Game of Thrones)跟寶可夢(Pokemon)的假資料都有
>> Faker::GameOfThrones.character
=> "Ned Stark"

>> Faker::GameOfThrones.character
=> "Stannis Baratheon"

>> Faker::Pokemon.name
=> "Pikachu"

做測試的時候用這個 Gem 來產生假資料相當方便!

在 Rails 專案裡使用 Gem

如果要在 Rails 專案中使用 Gem 的話,需要把要使用的 Gem 標註在專案目錄下的 Gemfile。打開 Gemfile,大概會長得像這樣:

  source 'https://rubygems.org'

  git_source(:github) do |repo_name|
    repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/")
    "https://github.com/#{repo_name}.git"
  end

  gem 'rails', '~> 5.1.0.rc1'
  gem 'sqlite3'
  gem 'puma', '~> 3.7'
  gem 'sass-rails', github: "rails/sass-rails"
  gem 'uglifier', '>= 1.3.0'
  gem 'coffee-rails', '~> 4.2'
  gem 'turbolinks', '~> 5'
  gem 'jbuilder', '~> 2.5'

  group :development, :test do
    gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
    gem 'capybara', '~> 2.13.0'
    gem 'selenium-webdriver'
  end

  group :development do
    gem 'web-console', '>= 3.3.0'
    gem 'listen', '>= 3.0.5', '< 3.2'
    gem 'spring'
    gem 'spring-watcher-listen', '~> 2.0.0'
  end

  gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

在這個檔案裡,你可以看到有些 Gem 的後面有加註版本號碼,有的沒有,這分別代表不同的意思:

沒加註版號

先從最簡單的來看。當後面沒有加註版本號碼的時候,像這樣:

  gem 'sqlite3'
  gem 'jquery-rails'

這樣的寫法將會在安裝的時候選用「最新的穩定(stable)版本」,要注意這裡的重點是「穩定」而不是「最新」。以 Rails 來說,假設最新的版本是 5.0.2 beta 4,但最新的「穩定」版本是 5.0.1 版,當沒有加註版本號的時候,它會選擇安裝 5.0.1 版本。

加註明確版號

例如像這樣:

  gem "rails", "5.0.1"

這相當明顯,意思就是說「我要安裝 rails 5.0.1 版」,這應該就不需要特別解釋了。

大於、小於版號

  gem 'uglifier', '>= 1.3.0'

我想這個用猜就猜得出來,就是要安裝大於或等於 1.3.0 版本。如果是這樣:

  gem 'rails', '>= 5.0.0.beta4', '< 5.1'

則是會選用在 5.0.0.beta4 跟 5.1 之間的版本。

差不多…

  gem 'coffee-rails', '~> 4.1.0'

這是指會選用 4.1.0 以上,但 4.2 以下(不含括 4.2)的最新版本。

為什麼這麼麻煩?舉個例子來說,例如版本號 4.2.6426 三個數字分別代表主要版號(Major)、次要版號(Minor)以及修訂版號(Patch),分別表示:

  • 主要版號:功能大改,公開的 API 做了不少修正,通常沒辦法向下相容。
  • 次要版號:加了某些新功能,但不影響其它功能,通常向下相容。
  • 修訂版號:對現有的功能做了小幅度的修正,通常可向下相容。

這是個不成文的規定(語義化版本),雖然沒有強制,但幾乎大部份的 Gem 作者都會依照這個規範。這個 ~> 的「差不多」寫法,可以確保不會因為套件昇級而把原本正常運作的系統弄壞了。

使用 Gem 來加速開發

介紹完了 Gemfile 裡的內容,接下讓我們利用現有的 Gem 來加速開發,舉個例子來說:

image

這個頁面的資料太多了,如果我想做分頁效果,每頁只想呈現 5 筆資料,通常你就得自己算每頁幾筆、現在是第幾頁、總共有幾頁這些數字(我數學不好,很不擅長算這種)。有位好心又很厲害的大大做了一個專門計算分頁的套件稱為 Kaminari,可以很輕鬆的完成這件事:

Step 1: 安裝套件

打開 Gemfile,加上這行:

  gem 'kaminari'

重要:更新 Gemfile 檔案內容後,別忘了要到該專案目錄底下執行 bundle install 指令,確保所有套件都有正常安裝。

Step 2: 修改程式碼

打開專案的 app/controllers/posts_controller.rb 檔案,把原來在 index 方法的 Post.all 做一些調整:

  class PostsController < ApplicationController
    before_action :set_post, only: [:show, :edit, :update, :destroy]

    def index
      @posts = Post.includes(:user).page(params[:page]).per(5)
    end

    ... [] ...
  end

那個 page 方法,是 Kaminari 這個套件專門拿來做分頁的方法,後面的 per(5) 就是「每頁有 5 筆資料」的意思。重新整理一下瀏覽器,應該會看到只剩 5 筆了:

image

(如果發生 page 方法找不到之類的錯誤訊息,可能重新啟動 Rails Server 之後就正常了)

但這樣還不夠,在畫面上好像還少了「上一頁」、「下一頁」的功能!沒關係,這個套件也幫你做好了。打開檔案 app/views/posts/index.html.erb,找一個你想要放分頁的地方:

  <p id="notice"><%= notice %></p>

  <h1>Posts</h1>

  <table>
    <thead>
    ...[略]...
    </tbody>
  </table>
  <br>

  <%= paginate @posts %>

  <br>
  <%= link_to 'New Post', new_post_path %>

那行 <%= paginate @posts %> 會幫你把分頁器做出來。重新整理一下畫面:

image

就這樣,寫沒幾行程式碼就把分頁功能做完了!

小結

善用現有的套件可以大幅的縮短開發時程。這些 Gem 的作者通常很愛現(稱讚意味),他們大多會在說明文件裡詳細介紹這個套件怎麼用(怕你不會用),所以,使用套件前應詳閱公開說明書(README),如果有任何問題,也都歡迎留 issue 給作者們,通常很快就會被解答。

另外,有兩個網站推薦給大家參考:

這兩個網站的影片都有介紹怎麼使用 Gem,其中雖然 RailsCasts 網站已停止更新,但網站上的內容仍非常有參考價值。

← 上一章:類別(Class)與模組(Module) 下一章:Model、View、Controller 三分天下 →

Comments