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

编辑:

所以 ack,我自己在实际使用那条线时遇到了各种问题。部分原因是我试图在类的方法中调用它。但是由于我只在类中调用一个方法(调用/运行其他所有方法),所以我现在拥有的最终工作版本是

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

显然 methodname 是一个实例方法,所以如果你的方法是类方法,你可以摆脱 new 。

于 2012-10-26T16:18:46.700 回答
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 << self不接受块;class_eval确实如此,因此它保留了局部变量的状态。我已经修改了我的解决方案以使用它。

于 2012-04-27T13:49:18.100 回答