v7.0.0
更多資訊請前往 rubyonrails.org: 更多在 Ruby on Rails

建立 Rails 外掛的基礎知識

Rails 外掛是核心框架的擴充套件或修改。外掛提供:

閱讀本指南後,您將瞭解:

本指南描述瞭如何構建一個測試驅動的外掛,它將:

出於本指南的目的,請假裝您是一名狂熱的觀鳥者。 你最喜歡的鳥是 Yaffle,你想建立一個外掛,讓其他開發者在 Yaffle 中分享 善良。

1 設定

目前,Rails 外掛被構建為 gems,gemified plugins。它們可以被共享 如果需要,使用 RubyGems 和 Bundler 的不同 Rails 應用程式。

1.1 產生一個 gemified 外掛。

Rails 附帶一個 rails plugin new 命令,它建立一個 用於開發具有能力的任何型別的 Rails 擴充套件的骨架 使用虛擬 Rails 應用程式執行整合測試。建立您的 帶有命令的外掛:

$ rails plugin new yaffle

通過尋求幫助來檢視用法和選項:

$ rails plugin new --help

2 測試您新產生的外掛

您可以導航到包含外掛的目錄,執行 bundle install 命令 並使用 bin/test 命令執行產生的測試。

你應該看到:

  1 runs, 1 assertions, 0 failures, 0 errors, 0 skips

這將告訴您一切都已正確產生,您已準備好開始新增功能。

3 擴充套件核心類

本節將解釋如何向 String 新增一個方法,該方法將在您的 Rails 應用程式中的任何位置可用。

在本例中,您將向 String 新增一個名為 to_squawk 的方法。首先,建立一個包含幾個斷言的新測試檔案:

# yaffle/test/core_ext_test.rb

require "test_helper"

class CoreExtTest < ActiveSupport::TestCase
  def test_to_squawk_prepends_the_word_squawk
    assert_equal "squawk! Hello World", "Hello World".to_squawk
  end
end

執行 bin/test 來執行測試。這個測試應該會失敗,因為我們還沒有實現 to_squawk 方法:

E

Error:
CoreExtTest#test_to_squawk_prepends_the_word_squawk:
NoMethodError: undefined method `to_squawk' for "Hello World":String


bin/test /path/to/yaffle/test/core_ext_test.rb:4

.

Finished in 0.003358s, 595.6483 runs/s, 297.8242 assertions/s.

2 runs, 1 assertions, 0 failures, 1 errors, 0 skips

太好了 - 現在您已準備好開始開發。

lib/yaffle.rb 中,新增 require "yaffle/core_ext"

# yaffle/lib/yaffle.rb

require "yaffle/railtie"
require "yaffle/core_ext"

module Yaffle
  # Your code goes here...
end

最後,建立 core_ext.rb 檔案並新增 to_squawk 方法:

# yaffle/lib/yaffle/core_ext.rb

class String
  def to_squawk
    "squawk! #{self}".strip
  end
end

要測試您的方法是否按規定執行,請使用外掛目錄中的 bin/test 執行單元測試。

  2 runs, 2 assertions, 0 failures, 0 errors, 0 skips

要在 action 中看到這一點,請切換到 test/dummy 目錄,啟動 bin/rails console,然後開始尖叫:

irb> "Hello World".to_squawk
=> "squawk! Hello World"

4 向 Active Record 新增“acts_as”方法

外掛中的一個常見模式是向 models 新增一個名為 acts_as_something 的方法。在這種情況下,你 想編寫一個名為 acts_as_yaffle 的方法,將 squawk 方法新增到您的 Active Record models。

首先,設定您的檔案,以便您擁有:

# yaffle/test/acts_as_yaffle_test.rb

require "test_helper"

class ActsAsYaffleTest < ActiveSupport::TestCase
end
# yaffle/lib/yaffle.rb

require "yaffle/railtie"
require "yaffle/core_ext"
require "yaffle/acts_as_yaffle"

module Yaffle
  # Your code goes here...
end
# yaffle/lib/yaffle/acts_as_yaffle.rb

module Yaffle
  module ActsAsYaffle
  end
end

4.1 新增類方法

這個外掛會期望你已經在你的 model 中添加了一個名為 last_squawk 的方法。但是,那 外掛使用者可能已經在他們使用的名為 last_squawk 的 model 上定義了一個方法 為了別的東西。該外掛將允許通過新增名為 yaffle_text_field 的類方法來更改名稱。

首先,編寫一個失敗的測試來顯示您想要的行為:

# yaffle/test/acts_as_yaffle_test.rb

require "test_helper"

class ActsAsYaffleTest < ActiveSupport::TestCase
  def test_a_hickwalls_yaffle_text_field_should_be_last_squawk
    assert_equal "last_squawk", Hickwall.yaffle_text_field
  end

  def test_a_wickwalls_yaffle_text_field_should_be_last_tweet
    assert_equal "last_tweet", Wickwall.yaffle_text_field
  end
end

當您執行 bin/test 時,您應該看到以下內容:

# 跑步:

..E

Error:
ActsAsYaffleTest#test_a_wickwalls_yaffle_text_field_should_be_last_tweet:
NameError: uninitialized constant ActsAsYaffleTest::Wickwall


bin/test /path/to/yaffle/test/acts_as_yaffle_test.rb:8

E

Error:
ActsAsYaffleTest#test_a_hickwalls_yaffle_text_field_should_be_last_squawk:
NameError: uninitialized constant ActsAsYaffleTest::Hickwall


bin/test /path/to/yaffle/test/acts_as_yaffle_test.rb:4



Finished in 0.004812s, 831.2949 runs/s, 415.6475 assertions/s.

4 runs, 2 assertions, 0 failures, 2 errors, 0 skips

這告訴我們,我們沒有要測試的必要 models(Hickwall 和 Wickwall)。 我們可以通過從 test/dummy 目錄:

$ cd test/dummy
$ bin/rails generate model Hickwall last_squawk:string
$ bin/rails generate model Wickwall last_squawk:string last_tweet:string

現在您可以通過導航到您的虛擬應用程式在您的測試資料庫中建立必要的資料庫表 和遷移資料庫。首輪:

$ cd test/dummy
$ bin/rails db:migrate

當你在這裡時,改變 Hickwall 和 Wickwall models,讓他們知道他們應該採取行動 像yaffle。

# test/dummy/app/models/hickwall.rb

class Hickwall < ApplicationRecord
  acts_as_yaffle
end
# test/dummy/app/models/wickwall.rb

class Wickwall < ApplicationRecord
  acts_as_yaffle yaffle_text_field: :last_tweet
end

我們還將新增程式碼來定義 acts_as_yaffle 方法。

# yaffle/lib/yaffle/acts_as_yaffle.rb

module Yaffle
  module ActsAsYaffle
    extend ActiveSupport::Concern

    class_methods do
      def acts_as_yaffle(options = {})
      end
    end
  end
end
# test/dummy/app/models/application_record.rb

class ApplicationRecord < ActiveRecord::Base
  include Yaffle::ActsAsYaffle

  self.abstract_class = true
end

然後您可以返回到外掛的根目錄 (cd ../..) 並使用 bin/test 重新執行測試。

# 跑步:

.E

Error:
ActsAsYaffleTest#test_a_hickwalls_yaffle_text_field_should_be_last_squawk:
NoMethodError: undefined method `yaffle_text_field' for #<Class:0x0055974ebbe9d8>


bin/test /path/to/yaffle/test/acts_as_yaffle_test.rb:4

E

Error:
ActsAsYaffleTest#test_a_wickwalls_yaffle_text_field_should_be_last_tweet:
NoMethodError: undefined method `yaffle_text_field' for #<Class:0x0055974eb8cfc8>


bin/test /path/to/yaffle/test/acts_as_yaffle_test.rb:8

.

Finished in 0.008263s, 484.0999 runs/s, 242.0500 assertions/s.

4 runs, 2 assertions, 0 failures, 2 errors, 0 skips

越來越近了... 現在我們將實現 acts_as_yaffle 方法的程式碼以使測試通過。

# yaffle/lib/yaffle/acts_as_yaffle.rb

module Yaffle
  module ActsAsYaffle
    extend ActiveSupport::Concern

    class_methods do
      def acts_as_yaffle(options = {})
        cattr_accessor :yaffle_text_field, default: (options[:yaffle_text_field] || :last_squawk).to_s
      end
    end
  end
end
# test/dummy/app/models/application_record.rb

class ApplicationRecord < ActiveRecord::Base
  include Yaffle::ActsAsYaffle

  self.abstract_class = true
end

當您執行 bin/test 時,您應該看到測試全部通過:

  4 runs, 4 assertions, 0 failures, 0 errors, 0 skips

4.2 新增實例方法

該外掛將向任何呼叫 acts_as_yaffle 的 Active Record 物件新增一個名為“squawk”的方法。 '吱吱' 方法將簡單地設定資料庫中欄位之一的 value。

首先,編寫一個失敗的測試來顯示您想要的行為:

# yaffle/test/acts_as_yaffle_test.rb
require "test_helper"

class ActsAsYaffleTest < ActiveSupport::TestCase
  def test_a_hickwalls_yaffle_text_field_should_be_last_squawk
    assert_equal "last_squawk", Hickwall.yaffle_text_field
  end

  def test_a_wickwalls_yaffle_text_field_should_be_last_tweet
    assert_equal "last_tweet", Wickwall.yaffle_text_field
  end

  def test_hickwalls_squawk_should_populate_last_squawk
    hickwall = Hickwall.new
    hickwall.squawk("Hello World")
    assert_equal "squawk! Hello World", hickwall.last_squawk
  end

  def test_wickwalls_squawk_should_populate_last_tweet
    wickwall = Wickwall.new
    wickwall.squawk("Hello World")
    assert_equal "squawk! Hello World", wickwall.last_tweet
  end
end

執行測試以確保最後兩個測試失敗並顯示包含“NoMethodError: undefined method `squawk'”的錯誤, 然後將 acts_as_yaffle.rb 更新為如下所示:

# yaffle/lib/yaffle/acts_as_yaffle.rb

module Yaffle
  module ActsAsYaffle
    extend ActiveSupport::Concern

    included do
      def squawk(string)
        write_attribute(self.class.yaffle_text_field, string.to_squawk)
      end
    end

    class_methods do
      def acts_as_yaffle(options = {})
        cattr_accessor :yaffle_text_field, default: (options[:yaffle_text_field] || :last_squawk).to_s
      end
    end
  end
end
# test/dummy/app/models/application_record.rb

class ApplicationRecord < ActiveRecord::Base
  include Yaffle::ActsAsYaffle

  self.abstract_class = true
end

最後一次執行 bin/test,您應該看到:

  6 runs, 6 assertions, 0 failures, 0 errors, 0 skips

使用 write_attribute 寫入 model 中的欄位只是外掛如何與 model 互動的一個示例,並不總是正確的使用方法。例如,您還可以使用:

send("#{self.class.yaffle_text_field}=", string.to_squawk)

5 發電機

產生器可以包含在您的 gem 中,只需在外掛的 lib/generators 目錄中建立它們即可。有關的更多資訊 產生器的建立可以在產生器指南中找到。

6 釋出您的 Gem

當前正在開發的 Gem 外掛可以從任何 Git 儲存庫輕鬆共享。要與他人分享 Yaffle gem,只需 將程式碼提交到 Git 儲存庫(如 GitHub)並在相關應用程式的 Gemfile 中新增一行:

gem "yaffle", git: "https://github.com/rails/yaffle.git"

執行 bundle install 後,您的 gem 功能將可用於應用程式。

當 gem 準備好作為正式版本共享時,它可以釋出到 RubyGems

或者,您可以從 Bundler 的 Rake 任務中受益。您可以檢視包含以下內容的完整列表:

$ bundle exec rake -T

$ bundle exec rake build
# 將 yaffle-0.1.0.gem 構建到 pkg 目錄中

$ bundle exec rake install
# 構建並安裝 yaffle-0.1.0.gem 到系統 gems

$ bundle exec rake release
# 建立標籤 v0.1.0 並構建並推送 yaffle-0.1.0.gem 到 Rubygems

有關將 gem 釋出到 RubyGems 的更多資訊,請參閱:釋出您的 gem

7 RDoc 文件

一旦您的外掛穩定並且您準備好部署,請幫其他人一個忙併記錄下來!幸運的是,為您的外掛編寫文件很容易。

第一步是使用有關如何使用外掛的詳細資訊更新 README 檔案。一些 key 的內容包括:

  • 你的名字
  • 如何安裝
  • 如何將功能新增到應用程式(常見用例的幾個示例)
  • 可以幫助使用者並節省時間的警告、陷阱或提示

一旦你的自述檔案是可靠的,請仔細閱讀並向開發人員將使用的所有方法新增 rdoc 註釋。將 # :nodoc: 註釋新增到未包含在公共 API 中的程式碼部分也是一種習慣做法。

一旦你的評論好了,導航到你的外掛目錄並執行:

$ bundle exec rake rdoc

7.1 參考

回饋

我們鼓勵您幫助提高本指南的品質。

如果您發現任何拼寫錯誤或資訊錯誤,請提供回饋。 要開始回饋,您可以閱讀我們的 回饋 部分。

您還可能會發現不完整的內容或不是最新的內容。 請務必為 main 新增任何遺漏的文件。假設是 非穩定版指南(edge guides) 請先驗證問題是否已經在主分支上解決。 請前往 Ruby on Rails 指南寫作準則 查看寫作風格和慣例。

如果由於某種原因您發現要修復的內容但無法自行修補,請您 提出 issue

關於 Ruby on Rails 的任何類型的討論歡迎提供任何文件至 rubyonrails-docs 討論區