💨

railsでenterprise機能を作成する方法

2025/01/12に公開

railsでenterprise機能を作成する方法について確認する。

chatwootの場合

enterprise機能のcommitは https://github.com/chatwoot/chatwoot/pull/3209 が初となる。
このcommitでは、enterpriseディレクトリを作成し、enterpise/LICENSEにエンタープライズライセンスを利用すると明記している。

作成したenterrprise機能を読み込むために、config/application.rbeager_load_pathsを使って読み込みパスに追加している。

# config/application.rb

    config.eager_load_paths += Dir["#{Rails.root}/enterprise/app/**"]

追加されたenterpriseディレクトリ配下の機能は、config/initializers/01_inject_enterprise_edition_module.rbを利用してprependすることで、app/ディレクトリの機能を拡張をしている。
機能自体は、gitlabの https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/initializers/0_inject_enterprise_edition_module.rb を参考に実装されている。

gitlabの場合

gitlab は CEとEE の2つのリポジトリを1つのリポジトリに統合した経緯がある。現在はgitlabリポジトリ1つで開発が進められており、enterprise機能はee/配下に格納されている。

https://about.gitlab.com/blog/2019/08/23/a-single-codebase-for-gitlab-community-and-enterprise-edition/

enterprise edition 開発の詳細について

Developing Enterprise Edition Features https://chatwoot.help/hc/handbook/articles/developing-enterprise-edition-features-38 に enterprise機能の開発について記載がある。

viewの場合

controllerはviewをレンダリングする際に、デフォルトではapp/views/ディレクトリパスのみを探索する。
prepend_view_path https://api.rubyonrails.org/classes/ActionView/ViewPaths.html#method-i-prepend_view_path を使って、enterpriseディレクトリ配下のviewを利用するようにcontrollerで指定する。

class EnterpriseBaseController
  before_action :prepend_view_paths

  def prepend_view_paths
    prepend_view_path 'enterprise/app/views/'
  end

controllerの場合

既存controllerの拡張

enterprise/app/controllers/enterprise/accounts_controller.rbで、moduleを作成し、拡張元で継承階層を指定する

# enterprise/app/controllers/enterprise/accounts_controller.rb
module Enterprise::AccountsController
  def self.prepended(base)
    base.before_action :prepend_view_paths
  end

  def prepend_view_paths
    prepend_view_path 'enterprise/app/views/'
  end
end
# app/controllers/enterprise/accounts_controller.rb
class AccountsController < ApplicationController
  ...
end
::AccountsController.prepend(Enterprise::AccountsController)

app/controllers/enterprise/accounts_controller.rbでprependで先読みすると、controllerの継承階層は次の通りとなる。

AccountsController.ancestors
=>
[Enterprise::AccountsController,
 AccountsController,
 ApplicationController,
...

Enterprise専用機能の場合

enterprise/app/controllers/articles_controller.rbで、classを作成する。prepend_view_pathsを使ってレンダリングするviewsディレクトリを調整する。

# enterprise/app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
  before_action :prepend_view_paths
  def prepend_view_paths
    prepend_view_path 'enterprise/app/views/'
  end
  ...

migrateについて

Data Models & Data Migrations
Users could be migrating between versions. So we always have to ensure that all the migrations are run for both the edition. The database schema needs to remain the same for both editions. In the Case of DataMigrations, you can have blank implementations for these migrations by conditionally excluding Enterprise specific DataModels with ChatwootApp.enterprise?

migrateについては、chatwootでは各バージョンへの移行がある可能性があるため、db/migrateで一本化されている。

まとめ

enterpriseディレクトリ配下にenterpriseライセンスを使って、enterprise機能を拡張していく。
enterpriseから移行する場合があるため、dbは一本化し、あくまでプランのひとつとして考える。

参考

gitlabのエディションについて

https://techblog.ap-com.co.jp/entry/2023/12/05/191705

eager_load_pathsについて

https://one-person.hatenablog.jp/entry/2019/01/16/181521

Discussion