覚え書き -- Rails から呼び出した Gem で Rails.root を使えるようにする

目的

Rails から呼び出した Gem で Rails.root を使えるようにすること

(以下の条件での対応方法は、結論、Gemfile で gem 'some_gem', require: false すること である)

目的のイメージ

Given

{Rails root}/Gemfile

gem 'my_gem', path: 'lib/my_gem'

{Rails root}/lib/my_gem.rb

require 'my_gem/somewhat'
module MyGem
end

{Rails root}/lib/my_gem/some_what.rb

module MyGem
  class SomeWhat
    p ::Rails.root
  end
end

{Rails root}/app/controllers/login.rb

class Login < ApplicationController
  require 'my_gem'
end

When

access to Rails app /login

Then

logger out the {Rails root} not nil

目的に対して起こる問題項目

  • Gem 単独では module ::Rails は定義されていない
  • Rails app と連携しなければいけない
  • Gem の呼び出し順序を守らなければいけない

問題項目の詳細

Gem 単独では module ::Rails は定義されていない

{Rails root}/lib/my_gem/some_what.rb が次のように構築されている

module MyGem
  class SomeWhat
    p ::Rails.root
  end
end
  • my_gem ディレクトリ直下で bundle exec irb から require 'my_gem' を実行したときの返り値について
    • log に {Rails root} の出力を期待するが、nil が返る
  • 理由: Gem 単体では Rails app の情報を持っていないため

Rails app と連携しなければいけない

{Rails root}/Gemfile

gem 'my_gem', path: 'lib/my_gem'

であるとする

  • Gem が Rails app と連携したので、rails c から、require 'my_gem' を実行すると
    • log に {Rails root} の出力を期待するが、nil が返る
  • 理由: Gem は Rails app が initialize を実行する前に読み込まれる為

Gem の呼び出し順序を守らなければいけない

'Gem が Rails app が initialize を実行する前に読み込まれる' ことを回避する

解決方法は {Rails root} の Gemfile を修正すること

{Rails root}/Gemfile

gem 'my_gem', path: 'lib/my_gem', reuqire: false
  • require: false を付けると、require 'my_gem' しなければ Gem の読み込みは行われない
  • (require: false を付けないと、gem 'my_gem' は Rails app が initialize される前に読み込まれる

  • rails c から、require 'my_gem' を実行すると

    • log に {Rails root} の出力を期待する、{Rails root} が実際に返ってくる

refferred to:

ruby - How do I get the root directory of a Rails app in a Gem - Stack Overflow