

つまってしまったので教えてください。  
Rais,Rubyは初めて書いているので、見当違いのことをしているかもしれません。

RailsからOpen3のcapture3メソッドを実行してデーモンを立ち上げたいのですが、「cannot load such
file」となってしまいました。

[code]

    # top_controller.rb(Railsからの呼び出し処理)
    
    def daemon_start
        cmd = "/bin/app start;"
        out, err, status = Open3.capture3(cmd)
        p out               
        p err              
        p status.exitstatus
    
        redirect_to root_path
    end
    
[/code]

  

[code]

    # app(呼び出されるapp)
    
    #!/usr/bin/env ruby
    require 'bundler/setup'
    require 'daemons'
    require 'pathname'
    
    base_dir = Pathname('../../').expand_path(__FILE__)
    Daemons.run(
      base_dir.join('bin/bot'),
      app_name: 'bot',
      dir_mode: :normal,
      dir: base_dir.join('tmp'),
      log_dir: base_dir.join('log'),
      log_output: true
    )
    
[/code]

  

[code]

    #表示内容(err)
    
    "bin/app:3:in `require': cannot load such file -- daemons (LoadError)\n\tfrom bin/app:3:i"
    
[/code]

  

以下、試してみたことです。

  * appをターミナルから実行  
→問題なく起動します。

  * ruby -Iでgemのパスを追加  
cmdを  
cmd = "ruby -I /Users/owner/.rvm/gems/ruby-2.2.0/gems/daemons-1.2.3/lib
/bin/app start;"  
と変えたところ、エラーは出なくなります。  
(-Iで/Users/owner/.rvm/gems/ruby-2.2.0/gems/を渡すと最初のエラーと変わらずです)

  * requireしているパスを絶対パスに変更  
同じ様に、エラーは出なくなります。

  * app内で$LOAD_PATH.unshiftする  
$LOAD_PATH.unshift('/Users/owner/.rvm/gems/ruby-2.2.0/gems/daemons-
1.2.3/lib')  
同じ様に、エラーは出なくなります。  
ただ、上2つもそうなのですが、appから呼ばれるbotの中でrequireしているgemが見つからないとなってしまいます。

  

[code]

    #そのときのエラー表示内容
    (botがrequireしているretryableの中でrequireしているファイルが見つからない)
    
    /Users/owner/.rvm/gems/ruby-2.2.0/gems/retryable-2.0.2/lib/retryable.rb:1:in `require': cannot load such file -- retryable/version (LoadError)
    
[/code]

【質問】  
appをターミナルから実行すれば正常に動いているので、パスが通ってないことが問題と考えています。  
使用するgemに上で試したことと同じ対応をすべてのgemにすればなんとかなるのかもしれませんですが、それなりの数があるため避けたいです。  
もっといい方法でパスを通す方法があるでしょうか？  
なんでもいいので教えていただきたいです。  
足りない情報があれば追記します。  
よろしくお願いします。

【環境】  
Rails:4.1  
Ruby:2.2.0(Railsで使用)  
Ruby:2.2.0(appで使用)


CC BY-SA 3.0
2015-10-19T14:43:27.280
17827
2018-07-23T04:12:41.660
2018-05-09T15:59:48.413
754
12840
question
ruby-on-rails ruby rubygems bundler
Open3やDaemonsを使って外部のRubyスクリプトを実行する際に、実行に必要なgemをロードできるようにしたい


Rails側でappの実行に必要となるgemをbundle installしたら、とりあえず起動できました。  
ですが、もっといい方法があるかもしれないので、引き続き回答をお待ちしています。


CC BY-SA 3.0
2015-10-20T03:06:44.257
17836
2015-10-20T03:06:44.257
12840
17827
answer


## 原因

[code]

    ## /bin/app の中の ##
    require 'bundler/setup'
    
[/code]

は何をやるかというと、カレントディレクトリから上に登っていって、最初に見つけた Gemfile の情報を利用して gem を LOAD_PATH
に設定します。さらにはその際に、グローバルでインストールされている gem の load_path 情報は、 bundler
が設定するものと被ってはいけないので、
[`clean_load_path`](https://github.com/bundler/bundler/blob/0c5d3b8c1f391aa5175321675ecd91ee6a1f231b/lib/bundler/shared_helpers.rb#L330)
でもってそれらを無視する挙動になっている様子です。なので、 bundler を利用する場合は、それが読み込む Gemfile に、すべての依存 gem
を記述しなければ、正しく動作しなさそうです。

## 今回何が起こったかを簡単にまとめると

  1. Rails のプロセスから `Open3` が呼ばれる (pwd はおそらく rails の root) その際、実行されたコマンドは pwd を rails から引き継ぐ。
  2. `bin/app` の `require 'bundler/setup'` の中で、 Gemfile の探索が行われる
  3. Rails 自身の Gemfile が発見される
  4. Rails の Gemfile が指定される gem たちでもって、 `LOAD_PATH` は設定されるが、そこには `daemon` などは含まれていない

## 取り得る対応

おそらく、 daemon やら app やらは rails とは独自に開発されている ruby のアプリケーションなのだと思います。 rails
とは独自であるならば、 Gemfile をそれ用に用意して、ひとつのプロジェクトとして設定しましょう。そして、 `Open3` を実行する際に、 app の
Gemfile が利用されるようにしましょう。

例えば次のように実行できるようにしたり:

[code]

    # top_controller.rb の中で
    cmd = 'cd /path/to/app/dir && bundle exec bin/app'
    Open3.capture3 cmd
    # ...
    
[/code]

もしくは、利用したい Gemfile を明示的に指定したりなど

[code]

    # app (呼び出される app)
    ENV['BUNDLE_GEMFILE'] = File.expand_path('../Gemfile', __dir__)
    # => (app ファイルがあるディレクトリからの相対パスでもって Gemfile を指定)
    
[/code]

また、 daemon のスクリプトまで含めて rails プロジェクトの管理下に入れてしまう、というのも手の一つではあります。


CC BY-SA 4.0
2018-05-09T15:43:42.307
43897
2018-05-10T02:26:40.553
2018-05-10T02:26:40.553
754
754
17827
answer