[英]Ruby and Rails: Metaprogramming variables to become class methods
我正在创建一个名为Configuration的模型,我有以下代码,并且我想通过使用元编程使它更加动态。
在用于配置模型的数据库的表中,我具有以下数据。
---------------------------------------------------------
variable_name as string | value in text
|
company_name | MyCompany
welcome_text | Welcome to MyCompany's App!
email_order_text | You've just created an account with MyCompany.
year_since | 2012
----------------------------------------------------------
class Configuration < ActiveRecord::Base
#nothing here yet
end
----------------------------------------------------------
当前,访问company_name的唯一方法是在rails控制台中执行以下操作:
configuration_company_name = Configuration.find_by_variable_name("company_name")
configuration_company_name.company_name
> "MyCompany"
我认为这是做事的不可接受的方式。 首先,每次有人检查公司名称时,它将访问数据库。 我认为,如果我可以在应用启动时加载它,而不必因为它在内存中而再次访问它,那会更好。 我该如何做些更动态的事情,以便可以像这样访问值“ MyCompany”。
Configuration.company_name
> "MyCompany"
这样做的原因是允许快速定制应用程序。
class Configuration < ActiveRecord::Base
# loads all the configuration variables to an in-memory
# static hash during the first access.
def self.[](n)
@config ||= {}.tap { |h| Configuration.all.each{ h[variable_name] = c.value}}
@config[n]
end
end
现在,您可以通过以下方式访问您的配置:
Configuration["company_name"]
如果您有大量配置参数,则通过访问初始化程序文件中的配置参数来预加载缓存可能会有所帮助。 如果您有1000个配置变量,则可能必须考虑将缓存迁移到memcached
等。
如果要以类方法访问配置参数:
class Configuration < ActiveRecord::Base
klass = class << self; self; end
Configuration.all.each{|c| klass.send(:define_method, c.variable_name){c.value}}
end
现在,您可以按以下方式访问参数:
Configuration.company_name
您在这里弄错的一件事,永远不会是Configuration.company_name
,就像访问Class属性而不是Object / Instance属性,
它应该是配置类的实例。 在另一个答案中使用@KandagaBoggu的方法仍然可以接受,但是几乎每次都可以访问数据库,也可以从Active Record的查询缓存中访问数据库。但是AR的查询缓存在特定操作(例如request)期间有效。 您可能想要使用类似Memcached的对象来使对象生存更长的时间。
当服务器启动时,我们可以将这些常量值移到yml
文件中,并将它们加载到变量中,并在需要时访问它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.