Rails3 提供了一些新的方法來擴充 Rails,其中最重要的算是了解 Railtie 吧。(我個人對 Generator 比較沒興趣)
Railtie 是 Rails 的核心程式,提供了 hooks 來修改啟動時的載入流程。Rails 的主要元件 (Action Mailer, Action Controller, Action View, Active Record, Active Resource) 都有 Railtie 來各自負責自己的載入流程。這樣設計的好處有 1. 主要元件也是可以抽換的(例如換 ORM) 2. 要在 Rails 裡 hook 變得十分乾淨,只要撰寫 railtie 即可,不像之前只能用 alias_method_chain。
不過,擴充 Rails 不一定會用到 Railtie。會需要實作的情境是你要在 Rails 框架啟動流程中做些互動,例如:
1. 建立 initializers
2. 新增 generator
3. 修改 Rails config.*
4. 訂閱 Rails +ActiveSupport::Notifications+
5. 新增 rake tasks
因此,我歸類出寫 Rails Plugin 的考量有 1. 要不要寫成 Gem 2. 需不需要用到 Railstie:
傳統 vender/plugin
傳統的 plugin 寫法依然適用,Rails 還是會去載入 plugin 目錄下的 init.rb。有趣的是,在 Rails 內部是把 plugin 自動包裝成一個 Rails::Plugin 類別,而這個 Plugin class 也是繼承自 Rails::Railtie 的。
包成 Rubygem
自從有了 Bundler 之後,包成 Gem 可以說是最佳實務了。透過標準的 Gem 格式,可以 1.設定 dependcncies 2. 有版號 version 3. 方便分享及安裝
如何包成 Gem 請參考 Rubygems 套件管理工具 這篇,很簡單的。
沒用到 railtie
Rails3 架構師 wycats 開示:”如果你沒有要 hook 在 Rails lifecycle 之中,不要用 Railtie。就如同一般的 Ruby library,你先 require 你需要的 Rails 元件,然後再修改或擴充即可” (例如 override 或 include something)
# in your_lib.rb
require "active_record"
require "your_lib/extensions"
class ActiveRecord::Base
include YourLib::Extensions
end
用到 railtie
如果你需要 hook 或載入 rake, generator 等,那就需要用到 railtie 了,該怎麼寫呢?
基本的寫法如下:
# my_new_gem/my_new_gem.rb
require 'rails'
class MyCoolRailtie < Rails::Railtie
# console 時載入
console do
Foo.console_mode!
end
# 載入 generator
generators do
require 'path/to/generator'
end
# 載入 rake tasks
rake_tasks do
require 'path/to/railtie.tasks'
end
# 建立 config/initializers
initializer "my_cool_railtie.boot_foo" do
Foo.boot(Bar)
end
end
除了上述這些,還有更多細微的 hook 如 config.after _initialize, config.middlewares, before_configuration, before_eager_load, before_initialize, to_prepare 等等族繁不及背載,如果沒仔細研究 Rails 的啟動流程恐怕也搞不清楚所有的差異。
如果你的 gem 不只給 rails 用,可以這樣寫:
# lib/my_new_gem/my_cool_railtie.rb
module MyNewGem
class MyCoolRailtie < ::Rails::Railtie
# Railtie code here
end
end
# lib/my_new_gem.rb
require 'my_new_gem/my_cool_railtie.rb' if defined?(Rails)
請期待下集 "Rails3: Engine 和 Plugins 系統",Rails::Engine 可以讓你包裝出獨立的 App 元件。
參考資料
Plugin Authors: Toward a Better Future
Rails 3 Plugins - Part 1 - The Big Picture
Extending Rails 3 with Railties
Class Rails::Railtie
發佈留言