9

Rails アプリケーションで、現在のランタイム状態に応じて任意のモジュールを含める必要がある状況があります。このモジュールは、特定の条件が真の場合にのみ必要なカスタム アプリケーション コードを提供します。基本的に、現在のコンテキストから会社の名前を取得し、それをモジュールとその定義のファイル名として使用しています。

p =  self.user.company.subdomain + ".rb"
if File.exists?(Rails.root + "lib/" + p)
include self.class.const_get(self.user.company.subdomain.capitalize.to_sym)
    self.custom_add_url
end

私のテスト モジュールは次のようになります。

module Companyx
    def custom_add_url
    puts "Calling custom_add_url"   
end 
end

コンソールで、これは実際に正常に動作します。ユーザーをプルして、次のようにモジュールを含めることができます。

[1] pry(main)> c = Card.find_by_personal_url("username")
[2] pry(main)> include c.class.const_get(c.user.company.subdomain.capitalize)=> Object
[3] pry(main)> c.custom_add_url

custom_add_url の呼び出し

モデルからインクルード行を実行しようとすると、

NoMethodError: undefined method `include' for #<Card:0x007f91f9094fb0>

include ステートメントがコンソールでは機能するが、モデル コードでは機能しない理由を誰かが提案できますか?

4

2 に答える 2

14

私も似たようなことをしています。この回答は役に立ちました: Rubyで文字列を定数に変換する方法は?

定数化メソッドを探していたことがわかりました。これは私のコードで使用している行です:

include "ModuleName::#{var.attr}".constantize

編集:

ですから、実際にその回線を自分で使用すると、さまざまな問題が発生しました。部分的には、クラスのメソッド内で呼び出そうとしていたためです。しかし、私はクラスで 1 つのメソッド (他のすべてを呼び出し/実行する) を呼び出しているだけなので、現在の最終的な作業バージョンは次のとおりです。

"ModuleName::#{var.attr}".constantize.new.methodname

明らかに methodname はインスタンス メソッドであるため、クラス メソッドの場合は new を削除できます。

于 2012-10-26T16:18:46.700 に答える
5

インクルードはクラスのメソッドです。

モデル内で呼び出す場合は、シングルトン クラスのコンテキストでコードを実行する必要があります。

p =  self.user.company.subdomain + ".rb"
if File.exists?(Rails.root + "lib/" + p)
myself = self
class_eval do
  include self.const_get(myself.user.company.subdomain.capitalize.to_sym)
end
self.custom_add_url

編集:

class << selfブロックを受け入れません。class_evalしたがって、ローカル変数の状態が保持されます。それを使用するようにソリューションを変更しました。

于 2012-04-27T13:49:18.100 に答える