因為遇到一個需求需要將Rails的View部分抽離到Gem裡面
也就是要實作一個具有Rails View功能的Gem
在此說明一下如何做到這件事情
1. 首先產生一個Gem
bundle gem product_quote
如此就會產生一個product_quote的 gem 所需要的基本文檔
接著要在.product_quote.gemspec裡面打上這個Gem的相關資料
#.product_quote.gemspec
# coding: utf-8
lib = File.expand_path('../lib', **FILE**) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'product_quote/version
Gem::Specification.new do |spec|
spec.name = "product_quote"
spec.version = ProductQuote::VERSION
spec.authors = ["Honor Lin"]
spec.email = ["[email protected]"]
spec.summary = "product_quote"
spec.description = "product_quote"
spec.homepage = ""
spec.license = "MIT"
spec.files = `git ls-files -z`.split("\x0")
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
spec.require_paths = ["lib"]
spec.add_development_dependency "bundler", "~> 1.7"
spec.add_development_dependency "rake", "~> 10.0"
end
接著執行
bundle
確認這個gem正確可以執行
如此初步的gem大致上完成
只是為了我們到時方便在主要的Rails Project引入這個Gem, 所以我們必須先記錄一個Gem在本機的路徑
假設為 ~/app/gems/product_quote
2. 建立Rails架構到Gem裡面
假設這個view在原先的Rails的架構會使用到的檔案目錄如下:
app/assets/javascripts/product_quote.js
app/assets/stylesheets/product_quote.scss
app/views/product_quote/.*
app/views/layout
將這幾個目錄和檔案,移到剛剛建立的Gem的根目錄
3. 讓Rails可以認得此Gem裡面的app目錄下的所有結構
要做到這件事情,就必須使用Rails的Engine
在此說明一下Engine的有幾個重點:
- 可以說是一個微型的Rails應用程式,完整的Rails應用程式是由Engine擴充來的
- Engine和Rails的應用程式分享共同的程式架構,也就是app/controller, app/model, app/views 等的是共通的
- Engine和Plugin可以說是密切相關,他們分享相同的/lib目錄,他們都是透過相同的命令方式產生,Engines可以說是全功能的Plugin,也就是說Engine可以是Plugin,Plugin也可以成為Engine
- Engine和Rails的應用程式的雖然共用空間結構,但是彼此是隔離的,都可以使用helper,例如articles_path去做對應相關的controller等的,沒有衝突,但是model,controller都可以透過namespaced去做區隔
要在Gem裡面實現Engine的功能只要實做一個繼承Rails::Engine 的class, 然後再Gem載入時的進入檔案,require這個class進來就可以
新增一個 engine.rb 到Gem的lib裡面
#ruby engine.rb
module ProductQuote
class Engine < ::Rails::Engine
end
end