我的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
如果我尝试从我的模型中运行include行,我会得到
NoMethodError: undefined method `include' for #<Card:0x007f91f9094fb0>
有人可以建议为什么include语句可以在控制台上运行,但不能在我的模型代码中运行?
答案 0 :(得分:11)
我正在做类似的事情。我觉得这个答案很有用: How to convert a string to a constant in Ruby?
原来我正在寻找constantize方法。这是我在我的代码中使用的行:
include "ModuleName::#{var.attr}".constantize
修改强>
所以ack,我遇到了各种问题,实际上我自己使用了那条线。部分是因为我试图在类中的方法中调用它。但由于我只在类中调用一个方法(调用/运行其他所有方法),我现在拥有的最终工作版本是
"ModuleName::#{var.attr}".constantize.new.methodname
显然,methodname是一个实例方法,所以如果你的是一个类方法,你可以摆脱新的方法。
答案 1 :(得分: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&lt;&lt;自我不接受障碍; class_eval,因此它保留局部变量的状态。我修改了我的解决方案以使用它。