2012-04-27 102 views
6

我在Rails應用程序中遇到了一種情況,我需要根據當前運行時狀態包含任意模塊。該模塊提供僅在特定條件成立時才需要的自定義應用程序代碼。基本上,我從當前上下文拉公司的名稱,並將它作爲文件名的模塊,其定義:Ruby:包含動態模塊名稱

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聲明可以在控制檯上工作,但不能在我的模型代碼中工作?

回答

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 

編輯:

類< <自不接受塊; class_eval確實,因此它保留了局部變量的狀態。我修改了我的解決方案以使用它。

+0

更改上下文似乎增加了一個複雜:自我對象不再存在(或更準確地說,它與用戶對象的關聯)?我嘗試過各種方法來解決這個問題,並閱讀這篇文章,瞭解這裏發生了什麼(http://yehudakatz.com/2009/11/15/metaprogramming-in-ruby-its-all-about-the-self/ ) 沒有成功。 – 2012-04-27 14:17:58

+0

哦,我的壞。基本上,新環境中的自我就是這個階級。這與做類評估類似。 我做過這樣的個人項目實驗。這個文件的頂部應該有所幫助:https://github.com/Hitonagashi/UndergroundFootball/blob/master/app/models/player。rb – 2012-04-27 14:27:14

+0

不太清楚我的理解:我認爲你正在談論代碼中的初始化方法,您將所有可能的技能都動態地添加爲類方法?我不明白這是如何適用於我的問題,因爲我無法將相關對象添加到該類。有什麼方法可以訪問實例的關係來在類塊內部編碼嗎? – 2012-04-27 14:35:05

8

我正在做類似的事情。我發現這個答案有用: How to convert a string to a constant in Ruby?

原來我正在尋找constantize方法。這是我用我的代碼行:

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

編輯:

所以ACK,我遇到了各種各樣的問題與實際使用該行自己。部分原因是因爲我試圖在類中的方法中調用它。但是,因爲我只在類調用一個方法(該方法調用/運行一切)最後工作版本我現在已經是

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

顯然,方法名是一個實例方法,所以你可以擺脫新的如果你的是一個類方法。