2012-04-27 8 views
6

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

module Companyx 
    def custom_add_url 
    puts "Calling custom_add_url" 
end 
end 

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 

私のテストモジュールは次のようになりますコンソールでは、これは実際に正常に動作します。誰もがなぜお勧めできます私は私のモデルから含める行を実行しようと

[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ステートメントはコンソール上で動作しますが、私のモデルコードでは動作しませんか?

答えて

5

Includeはクラスのメソッドです。

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

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 

EDIT:

クラス< <自己ブロックを受け入れません。 class_evalは、ローカル変数の状態を保持します。私はそれを使用するために私のソリューションを変更しました。

+0

コンテキストを変更すると、自己オブジェクトが存在しなくなる(または、正確には、ユーザーオブジェクトとの関連付けが複雑になる)ようです。私はこれを回避し、ここで何が起こっているのかを理解するためにこの記事を読むために様々な方法を試しました(http://yehudakatz.com/2009/11/15/metaprogramming-in-ruby-its-all-about-the-self/ )成功しません。 –

+0

ああ、私の悪い。基本的には、新しいコンテキストの自己がクラスです。これは、クラス評価を行うのと同じです。 私は個人的なプロジェクトの実験としてこのようなことをしました。このファイルの先頭には次のような情報が必要です。https://github.com/Hitonagashi/UndergroundFootball/blob/master/app/models/playerrb –

+0

私は理解していません:クラスメソッドとしてすべてのスキルを動的に追加しているコードのinitializeメソッドについて話していると思いますか?クラスに関連するオブジェクトを追加することができないため、私の問題にどのように当てはまるのか分かりません。インスタンスとクラスブロック内のコードとの関係にアクセスする方法はありますか? –

8

私も同様のことをしています。この回答が役に立ちました: How to convert a string to a constant in Ruby?

私はconstantizeメソッドを探していました。これは私が私のコードで使用しているラインです:

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

編集:

ので、ACK、私は実際にそのラインに自分自身を使用してさまざまな問題に遭遇しました。部分的に私はそれをクラス内のメソッドの中で呼び出そうとしていたからです。私は唯一のクラスで1つのメソッドを呼んでいるので、しかし、あなたは新しい取り除くことができるように私が持っている最終的な作業のバージョンは今、methodnameはそのインスタンスメソッドで明らかに

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

です(呼び出す/他のすべてを実行します)あなたがクラスメソッドである場合。

関連する問題